home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2010 Summer - Disc 1 / WN_Ete2010_CD1.iso / Onglet5 / Weezo / Weezo setup.exe / {code_appDir} / www / includes / resourceConfigFunctions.php < prev    next >
PHP Script  |  2010-05-19  |  78KB  |  1,933 lines

  1. <?php
  2. /**
  3.  * Resource configuration common functions
  4.  *
  5.  * This script is either included by accounts.php (if accessed from a browser) or directly called by embeded browser of application
  6.  *
  7.  * PHP version 5
  8.  *
  9.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  10.  * that is available through the world-wide-web at the following URI:
  11.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  12.  * the PHP License and are unable to obtain it through the web, please
  13.  * send a note to license@php.net so we can mail you a copy immediately.
  14.  *
  15.  * @category   NA
  16.  * @package    NA
  17.  * @author     Nicolas Bruley / Peer 2 World <contact@weezo.net>
  18.  * @copyright  2005-2009 Nicolas Bruley / Peer 2 World
  19.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  20.  * @version    CVS: $Id:$
  21.  * @link       http://www.weezo.net
  22.  * @since      File available since Release 1.0.0
  23.  */
  24.  
  25.  
  26. /*
  27.  ***************************************************************************************************************************
  28.  * Wrappers
  29.  ***************************************************************************************************************************
  30.  */
  31.  
  32. /**
  33.  * @desc Set configuration rights
  34.  *             Display error page if config not allowed
  35.  * @return boolean : true if user may only modifiy non-sensitive parameters, for this session only,
  36.  *                     or false if user has full-configuration rights
  37.  *
  38.  */
  39. function rcConfigRights($limitedConfigAllowed=false){
  40.     global $includedByResourceConfig;
  41.  
  42.     // If included by resourceConfig.php script: access control has already beed done (double check anyway)
  43.     if(isset($includedByResourceConfig) && (cfIsInApp() || (cfUGetVar('administrator') && ($_SERVER['REMOTE_ADDR']==='127.0.0.1' || cfGGetVar('remoteAdministrationAuthorized'))))) return false;
  44.  
  45.     // If limited config allowed, initialize limited configuration environment
  46.     if($limitedConfigAllowed) {
  47.         rcInitLimitedConfig();
  48.         return true;
  49.     }
  50.  
  51.     // Else forbid access and log
  52.     cfLog('administration : unauthorized access attempt by '.$_SERVER['REMOTE_ADDR'], LOG_INF);
  53.     require_once(INCLUDE_DIR.'outputFunctions.php');
  54.     outDisplayErrorPage(cfcaption('errorRemoteAdministrationNotAuthorized')); // If no access right, display error page and exit
  55. }
  56.  
  57. /**
  58.  * @desc Return resource name (caption)
  59.  *
  60.  * @param string $type
  61.  * @param string $subType
  62.  * @param array $rData: optional: resource definition
  63.  * @return string UTF8 encoded caption
  64.  */
  65. function rcResourceCaptionUTF8($type, $subType ,&$rData=null){
  66.     if(cfCaptionExist($type.'_'.$subType.'-name')) return cfCaption($type.'_'.$subType.'-name');
  67.     if(cfCaptionExist(strtolower($type.'_'.$subType.'-name'))) return cfCaption(strtolower($type.'_'.$subType.'-name'));
  68.     if($rData===null) $rData=cfMGetVar('weezoResourceDefinition'.strtolower($type).strtolower($subType));
  69.     if(isset($rData['describer'][cfGGetVar('language')]['name'])) return $rData['describer'][cfGGetVar('language')]['name'];
  70.     return cfUTF8Encode($subType);
  71. }
  72.  
  73. /**
  74.  * @desc Return resource description
  75.  *
  76.  * @param string $type
  77.  * @param string $subType
  78.  * @param array $rData: optional: resource definition
  79.  * @return string UTF8 encoded caption
  80.  */
  81. function rcResourceDescriptionUTF8($type, $subType ,&$rData=null){
  82.     if(cfCaptionExist($type.'_'.$subType.'-description')) return cfCaption($type.'_'.$subType.'-description');
  83.     if(cfCaptionExist(strtolower($type.'_'.$subType.'-description'))) return cfCaption(strtolower($type.'_'.$subType.'-description'));
  84.     if($rData===null) $rData=cfMGetVar('weezoResourceDefinition'.strtolower($type).strtolower($subType));
  85.     if(isset($rData['describer'][cfGGetVar('language')]['description'])) return $rData['describer'][cfGGetVar('language')]['description'];
  86.     return cfCaption('genNoDescription');
  87. }
  88.  
  89. /**
  90.  * @return  mixed array : parsed file (or false if file couldn't be opened)
  91.  * @param string $fileName : file name (not including path)
  92.  * @desc parse a user file
  93. */
  94. function rcParseUserFile($fileName){
  95.     $file=cfAppDataDir().'/'.$fileName;
  96.     if(!file_exists($file)) return false;
  97.     return cfParse_ini_file($file,true);
  98. }
  99. /**
  100.  * @return  mixed array : parsed file (or false if file couldn't be opened)
  101.  * @param string $fileName : file name (not including path)
  102.  * @desc parse a resource file
  103. */
  104. function rcParseResourceFile($fileName){
  105.     $file=cfAppDataDir().'/'.$fileName;
  106.     if(!file_exists($file)) return false;
  107.     return cfParse_ini_file($file, true);
  108. }
  109. /**
  110.  * @return  mixed array : parsed file (or false if file couldn't be opened)
  111.  * @desc parse the transfers file
  112. */
  113. function rcParseTransfersFile(){
  114.     $file=cfAppDataDir().'/transfers.txt';
  115.     if(!file_exists($file)) return false;
  116.     return cfParse_ini_file($file,true);
  117. }
  118.  
  119. /**
  120.  * @return mixed: filename if success, false if user file couldn't be written
  121.  * @param mixed array $params : complete user configuration
  122.  * @param string $fileName : file name (not including path). If not set, try to detect filename from $params
  123.  * @param bool $commit: true to update UI and to reload all users (should be used when a single user is updated)
  124.  * @desc Write .usr user configuration file, from $params array of parameters
  125. */
  126. function rcWriteUserFile($params, $fileName='',$commit=true){
  127.     if(!$fileName){
  128.         if(isset($params['configFilename'])) $fileName=$params['configFilename'];
  129.         else {
  130.             cfLog('administration : error saving user file, filename not found', LOG_ER);
  131.             return false;
  132.         }
  133.     }
  134.     // Save file
  135.     if(!cfWriteIniFile($params,cfAppDataDir().'/'.$fileName,true)){
  136.         cfLog('administration : error saving '.$fileName.' user file', LOG_ER);
  137.         return false;
  138.     }
  139.     //cfServerSendCommand('refreshUser file="'.$fileName.'"');
  140.     cfLog('administration : '.$fileName.' user file modified by '.$_SERVER['REMOTE_ADDR'], LOG_DBG);
  141.  
  142.     // Reload users into memory
  143.     require_once(INCLUDE_DIR.'initFunctions.php');
  144.     ifLoadUsers();
  145.     return $fileName;
  146. }
  147.  
  148. /**
  149.  * @desc Update several user files
  150.  *
  151.  * @param array $users: array of user config array
  152.  */
  153. function rcWriteUserFiles($users){
  154.     if(!is_array($users) || count($users)==0) return ;
  155.  
  156.     // Save to disk
  157.     $filenames=array();
  158.     foreach ($users as $userConfig) $filenames[]=rcWriteUserFile($userConfig,'',false);
  159.  
  160.     // Update UI
  161.     $nb=0;
  162.     $command='refreshUsers';
  163.     foreach ($filenames as $filename) if($filename) $command.=' file'.($nb++).'="'.$filename.'"';
  164.  
  165.     if($nb) cfServerSendCommand($command);
  166.  
  167.     // Reload all users
  168.     ifLoadUsers();
  169. }
  170.  
  171. /**
  172.  * @desc return an array id=>properties of users bound to resource
  173.  *
  174.  * @param string $filename: resource id OR resource config filename
  175.  * @return array
  176.  */
  177. function rcResourceGetUsers($filename){
  178.     $bound=array();
  179.     // If id passed, search matching filename
  180.     if(!strpos($filename,'.res')){
  181.         if(!($filename=cfArrayItem(cfMGetVar('weezoResourcesList'),$filename))) return array();
  182.     }
  183.     // Browse users
  184.     foreach (cfMGetVar('weezoUsers') as $id=>$user){
  185.         $i=0;
  186.         // Browse user's resources
  187.         while (isset($user['resource'.$i]['file'])) {
  188.             // If searched resource matches
  189.             if($user['resource'.$i]['file']==$filename){
  190.                 $bound[$id]=$user;
  191.                 break;
  192.             }
  193.             $i++;
  194.         }
  195.     }
  196.     return $bound;
  197. }
  198.  
  199. /**
  200.  * @return boolean : true if success, false if user file couldn't be written
  201.  * @param mixed array $params : complete user configuration
  202.  * @param string $fileName : file name (not including path)
  203.  * @param string $forceCommitToApp: true to force application resource update
  204.  * @desc Write .res resource configuration file, from $params array of parameters
  205. */
  206. function rcWriteResourceFile($params, $fileName=false, $forceCommitToApp=false){
  207.     global $resourceNameModified;
  208.     global $limitedConfig;
  209.     global $originalResourceData;
  210.  
  211.     // Remove data directly linked to resource definition
  212.     unset($params['definition']);
  213.  
  214.     // Check if config has been modified
  215.     if(isset($originalResourceData)){
  216.         $commit=false;
  217.         foreach ($params as $k=>$v){
  218.             if(!isset($originalResourceData[$k])){$commit=true;break;}
  219.             if(is_array($v)){
  220.                 foreach ($v as $k2=>$v2){
  221.                     if($originalResourceData[$v][$k2]!==$v2) {$commit=true;break 2;}
  222.                 }
  223.             }
  224.             elseif ($v!==$originalResourceData[$k]){
  225.                 if($k!=='path' || str_replace('*appDir*',cfAppDataRootDir(),$v)!==$originalResourceData[$k]){$commit=true;break;}
  226.             }
  227.         }
  228.         // Config not modified - exit
  229.         if(!$commit) return true;
  230.     }
  231.  
  232.     if(!$fileName && isset($params['resourceFilename'])) $fileName=$params['resourceFilename'];
  233.     elseif(!$fileName && isset($params['resourceName'])) $fileName=$params['resourceName'].'.res';
  234.  
  235.  
  236.     // Limited configuration : apply changes to current resource data
  237.     if($limitedConfig) {
  238.         // Apply
  239.         foreach ($params as $key=>$value) if($value!=cfRGetVar($key)) cfRSetVar($key,$value);
  240.         //$_SESSION['res'][$_SESSION['activeResourceId']]=$params;
  241.         // Reload opener window and close this window
  242.         if(count($_POST)) echo '<script type="text/javascript">function onLoadFunc(){applyChanges()}</script>';
  243.         else
  244.             echo <<<EOT
  245. <script type="text/javascript">
  246. function onLoadFunc(){winMe.resizeInnerTo(545,dgi('limitedConfigFrame').offsetHeight+10,1)}
  247. </script>
  248. EOT;
  249.         return true;
  250.     }
  251.  
  252.     // Normal config : commit new data to resource config file
  253.     $newResource=!file_exists(cfAppDataDir().'/'.$fileName);
  254.     if(!cfWriteIniFile($params,cfAppDataDir().'/'.$fileName,true)){
  255.         cfLog('administration : error saving '.$fileName.' resource file', LOG_ER);
  256.         return false;
  257.     }
  258.  
  259.     // Update in-memory resource data
  260.     require_once(INCLUDE_DIR.'initFunctions.php');
  261.     ifLoadResource($fileName,$params);
  262.  
  263.     if($forceCommitToApp || $newResource || isset($resourceNameModified)) {
  264.         // Update in application (still needed as filename modification in DB are done through app)
  265.         cfServerSendCommand('refreshResource file="'.$fileName.'" resourceNameModified="true"');
  266.  
  267.         // Reset users-resources associations
  268.         if($newResource) {
  269.             require_once(INCLUDE_DIR.'initFunctions.php');
  270.             ifResetResourcesUsers(false,false);
  271.         }
  272.     }
  273.  
  274.     cfLog('administration : '.$fileName.' configuration file modified by '.$_SERVER['REMOTE_ADDR'], LOG_DBG);
  275.     return true;
  276. }
  277.  
  278. /**
  279.  * @desc Create a new resource
  280.  *
  281.  * @param string $type
  282.  * @param string $subType
  283.  * @param array $resourceData (optional): preset resource data
  284.  * @return string resource configuration filename
  285.  */
  286. function rcCreateResource($type,$subType,$resourceData=false){
  287.     // Clean $type & $subType
  288.     $type    =str_replace('/','',str_replace('\\','',str_replace('..','',$type)));
  289.     $subType=str_replace('/','',str_replace('\\','',str_replace('..','',$subType)));
  290.  
  291.     // Verify it's actually a resource
  292.     if(is_dir(cfAppDocRoot().'/res/'.$type.'/'.$subType)){
  293.         // Generate resource file
  294.         $rData=rcGetResourceDefinition($type,$subType);
  295.         $tmpResource=array();
  296.         if(is_array($resourceData)) $tmpResource=$resourceData;
  297.         if(!isset($tmpResource['name'])) $tmpResource['name']=cfUTF8Decode($rData['name']);
  298.         $tmpResource['type']=$type;
  299.         $tmpResource['subType']=$subType;
  300.         $tmpResource['id']=substr(sha1(rand().rand().rand()),0,10);
  301.         // Get default parameters if present
  302.         if(file_exists(cfAppDocRoot().'/res/'.$type.'/'.$subType.'/defaultConfig.php')){
  303.             $defaultConfig=cfParse_ini_file(cfAppDocRoot().'/res/'.$type.'/'.$subType.'/defaultConfig.php');
  304.             foreach ($defaultConfig as $key=>$value) if($key!='name' && $key!='type' && $key!='subType') $tmpResource[$key]=$value;
  305.             unset($defaultConfig);
  306.         }
  307.         // Write resource file
  308.         $nb=1;
  309.         while(file_exists(cfAppDataDir().'/'.$type.$subType.$nb.'.res')) $nb++;
  310.         rcWriteResourceFile($tmpResource,$type.$subType.$nb.'.res');
  311.         return $type.$subType.$nb.'.res';
  312.     }
  313.     return false;
  314. }
  315.  
  316. /**
  317.  * @desc Add an asynchronous javascript or HTML insertion command
  318.  *
  319.  * @param string $xmlNode: xml node generated by cfAsyncXMLInnerHTMLbyId(), cfAsyncXMLJSaction()...
  320.  */
  321. function rcAddAsyncResponse($xmlNode){
  322.     if(!isset($_ENV['rcAsyncResponse'])) $_ENV['rcAsyncResponse']=$xmlNode;
  323.     else $_ENV['rcAsyncResponse'].=$xmlNode;
  324. }
  325.  
  326. /**
  327.  * @desc : return path from server root of image located in resource directory
  328.  * @return : string : path
  329.  *
  330.  * @param string $fileName : name of image (without path)
  331.  */
  332. function rcResourceImage($fileName){
  333. global $resourceData;    return '/res/'.$resourceData['type'].'/'.$resourceData['subType'].'/'.$fileName;
  334. }
  335.  
  336. /**
  337.  * @desc Copy $resourceData into $_SESSION['res'][0] so functions using cfRgetVar / cfRSetVar can be used by configuration scripts
  338.  *
  339.  */
  340. function rcCopyResourceDataToRVar(){
  341.     global $resourceData;
  342.     $_SESSION['activeResourceId']=0;
  343.     $_SESSION['res'][0]=$resourceData;
  344. }
  345.  
  346. /**
  347.  * @desc Create resource data directory if needed
  348.  *
  349.  */
  350. function rcCreateResourceDataDir(){
  351.     global $resourceData;
  352.     global $fileName;
  353.     if($resourceData['resourceDataDirAccessAllowed']){
  354.     $subTypeDir = cfAppDataDir()."/res/".$resourceData['type'] ."/".$resourceData['subType'];if(!file_exists($subTypeDir)) @mkdir($subTypeDir);
  355.     $dataDir = cfAppDataDir()."/res/".$resourceData['type'] ."/".$resourceData['subType']."/". cfFileWithoutExtension($fileName);if(!file_exists($dataDir)) @mkdir($dataDir);
  356.     }
  357. }
  358.  
  359. /**
  360.   * @desc set a PHP callback function that will be called on resource data change
  361.   *        Callback function must have 2 parameters :
  362.           - string $dataName
  363.           - mixed $previousDataValue
  364.   *
  365.   * @param string $functionName
  366.   */
  367. function rcSetModifiedValuePHPFunction($functionName){
  368.     global $modifiedValuePHPFunction;
  369.     $modifiedValuePHPFunction=$functionName;
  370. }
  371.  
  372.  
  373. /**
  374.  * @desc Insert / update key/value pair in current user's .usr file
  375.  * @param array $values
  376.  *
  377.  */
  378. function rcUserSaveValues($values){
  379.     // Save only if single user profile
  380.     if($_SESSION['user']['accountType']!='singleUser' && !$_SESSION['user']['administrator']) return;
  381.     $needSave=false;
  382.  
  383.     // Load original user data
  384.     $users=cfMGetVar('weezoUsers');
  385.     $userConfig=$users[$_SESSION['user']['id']];
  386.  
  387.     // Apply new entries
  388.     foreach ($values as $key=>$value) if(!isset($userConfig[$key]) || $userConfig[$key]!=$value){
  389.         $userConfig[$key]=$value;
  390.         $modified=true;
  391.     }
  392.  
  393.     // Commit to file and inform app
  394.     if(isset($modified)) rcWriteUserFile($userConfig, basename($_SESSION['user']['configFilename']));
  395. }
  396.  
  397. /**
  398.  * @desc Get main info on type/subtype resource
  399.  *
  400.  * @param string $type
  401.  * @param string $subType
  402.  * @return array (type,subType,iconFile,describer)
  403.  */
  404. function rcGetResourceDefinition($type, $subType){
  405.     $res=cfMGetVar('weezoResourceDefinition'.strtolower($type).strtolower($subType));
  406.     $res['name']=rcResourceCaptionUTF8($type,$subType,$res);
  407.     $res['description']=rcResourceDescriptionUTF8($type,$subType,$res);
  408.     return $res;
  409. }
  410.  
  411. /**
  412.  * @desc Add a resource to one or more users
  413.  *
  414.  * @param string $rid: resoure id OR resource config filename
  415.  * @param mixed $uids: 'all', user id or array of users ids
  416.  */
  417. function rcResourceAddToUsers($rid,$uids){
  418.     // If $rid is resource config filename, find resource id
  419.     if(strpos($rid,'.res')){
  420.         foreach (cfMGetVar('weezoResourcesList') as $k=>$v) if($v==$rid){
  421.             $rid=$k;
  422.             $rFilename=$v;
  423.             break;
  424.         }
  425.         if(!isset($rFilename)) return false;
  426.     }
  427.     // Get resource config filename from rid (as filename is resource identifier in user description)
  428.     elseif(!($rFilename=cfArrayItem(cfMGetVar('weezoResourcesList'),$rid))) return false;
  429.  
  430.     // Get resource definition
  431.     $rd=cfMGetVar('weezoResData'.$rid);
  432.  
  433.     $updated=0;
  434.     // Browse users to find concerned user
  435.     if(!is_array($uids) && $uids!=='all') $uids=array($uids);
  436.     foreach ($users=cfMGetVar('weezoUsers') as $uid=>$user) if($uids=='all' || @$_POST['user']===$uid || in_array($uid,$uids)) {
  437.         $max=-1;
  438.         $alreadyBound=0;
  439.         // Count resources to append at end, and check this user doesn't already have this resource
  440.         foreach ($user as $k=>$v) if(cfCmpLeft($k,'resource') && isset($v['file'])){
  441.             // If resource already bound to user, exit
  442.             if($v['file']==$rFilename) {
  443.                 $alreadyBound=1;
  444.                 break;
  445.             }
  446.             $max=max($max,substr($k,8)); // $k="resourceX"
  447.         }
  448.         if($alreadyBound) continue;
  449.  
  450.         // Add resource to user
  451.         $user['resource'.($max+1)]=array('type'=>$rd['type'],'subType'=>$rd['subType'],'file'=>$rFilename);
  452.         rcWriteUserFile($user);
  453.         $updated++;
  454.     }
  455.     // If at least one user updated, rebind users / resources in memory
  456.     if($updated){
  457.         require_once(INCLUDE_DIR.'initFunctions.php');
  458.         ifResetResourcesUsers();
  459.     }
  460. }
  461.  
  462. /*
  463.  ***************************************************************************************************************************
  464.  * Misc actions
  465.  ***************************************************************************************************************************
  466.  */
  467.  
  468.  
  469. /**
  470.  * @desc Unlink all thumbnails of current resource
  471.  * @return int: number of deleted files
  472.  *
  473.  */
  474. function rcThumbnailsClear($path=false){
  475.     if(!$path){
  476.         global $resourceData;
  477.         global $fileName;
  478.         $path=cfAppDataDir()."/res/".$resourceData['type'] ."/".$resourceData['subType']."/". cfFileWithoutExtension($fileName);
  479.     }
  480.     $nb=0;
  481.     // Clear subdir's thumbnails
  482.     foreach (glob($path.'/*',GLOB_ONLYDIR) as $completeFilename) $nb+=rcThumbnailsClear($completeFilename);
  483.  
  484.     // Unlink empty directories
  485.     foreach (glob($path.'/*',GLOB_ONLYDIR) as $completeFilename) @rmdir($completeFilename);
  486.  
  487.     // Clear current dir's thumbnails
  488.     foreach (glob($path.'/*.jpg') as $completeFilename) {
  489.         @unlink($completeFilename);
  490.         $nb++;
  491.     }
  492.  
  493.     // Return number of deleted files
  494.     return $nb;
  495. }
  496.  
  497. /**
  498.  * @desc Delete resource file and inform application
  499.  *
  500.  * @param string $fileName
  501.  */
  502. function rcDeleteResource($fileName){
  503.     // Remove file
  504.     if(!file_exists(cfAppDataDir().'/'.$fileName)) return true;
  505.     @unlink(cfAppDataDir().'/'.$fileName);
  506.  
  507.     // Remove from memory
  508.     $rl=cfMGetVar('weezoResourcesList');
  509.     foreach ($rl as $rid=>$rFileName) if($rFileName==$fileName){
  510.         @cfMUnsetVar('weezoResData'.$rid);
  511.         unset($rl[$rid]);
  512.         cfMSetVar('weezoResourcesList',$rl);
  513.         break;
  514.     }
  515.     // Inform app
  516.     cfServerSendCommand('deleteResource file="'.$fileName.'"');
  517.  
  518.     // Reset users-resources associations
  519.     require_once(INCLUDE_DIR.'initFunctions.php');
  520.     ifResetResourcesUsers(false,false);
  521.     return true;
  522. }
  523.  
  524. /**
  525.  * @return boolean : true if success, false if user file couldn't be deleted
  526.  * @param string $fileName : file name (not including path)
  527.  * @desc Delete .usr user configuration file, and inform application to remove user from list
  528. */
  529. function rcDeleteUser($fileName){
  530.     // Delete file
  531.     @unlink(cfAppDataDir().'/'.$fileName);
  532.  
  533.     // Inform application (which delete file (once again), update general.ini, and it's internal controls)
  534.     cfServerSendCommand('userDeleted file="'.$fileName.'"');
  535.     cfLog('administration : '.$fileName.' user file deleted by '.$_SERVER['REMOTE_ADDR'], LOG_DBG);
  536.  
  537.     // Reload users into memory
  538.     require_once(INCLUDE_DIR.'initFunctions.php');
  539.     ifLoadUsers();
  540.  
  541.     return true;
  542. }
  543.  
  544.  
  545.  
  546. /*
  547.  ***************************************************************************************************************************
  548.  * New resource form
  549.  ***************************************************************************************************************************
  550.  */
  551.  
  552. /**
  553.  * @desc Insert new resource popup and scripts
  554.  *
  555.  * @param array $allowed: array(type=>array(subtype1,subtype2,...), ...) of allowed new resource. If not set, all resources are allowed
  556.  * @param bool $standalone: true if form is displayed in standalone webbrowser (UI)
  557.  */
  558. function rcNewResourceForm($allowed=false,$standalone=false){
  559.     $resourcesDefinitions=cfMGetVar('weezoResourcesDefinitions');
  560.     $users=cfMGetVar('weezoUsers');
  561.  
  562.     // Re-order explorer resources
  563.     $explOrder=array('Photo1','File1','music3','Video','multimedia','music1','music2','musicWinamp');
  564.     $expl=array(); foreach ($explOrder as $k) $expl[$k]=$resourcesDefinitions['explorer'][$k];
  565.     foreach ($resourcesDefinitions['explorer'] as $k=>$v) if(!isset($expl[$k])) $expl[$k]=$v;
  566.     $resourcesDefinitions['explorer']=$expl;
  567.  
  568.     // Prepare resource tree
  569.     $tree=array('ico'=>outIcon('resources'),'path'=>'top','label'=>'','sub'=>array());
  570.  
  571.     // For each types
  572.     foreach (array('explorer','administration','webcam','website','blog','bookmarks','tv','misc') as $typeName=>$type) if(isset($resourcesDefinitions[$type]) && (!$allowed || isset($allowed[$type]))){
  573.         // No administration config in remote admin
  574.         if($type=='administration' && !cfIsInApp()) continue;
  575.  
  576.         // Init type's node
  577.         $tree['sub'][$type]=array(
  578.             'ico'=>'/res/'.$type.'/resourceIconSmall.'.((file_exists(cfAppDocRoot().'/res/'.$type.'/resourceIconSmall.png'))?'png':'gif'),
  579.             'label'=>'<b>'.cfCaption('res'.ucfirst($type)).'</b>',
  580.             'unfolded'=>true,
  581.             'sub'=>array());
  582.  
  583.         $nbSub=0;
  584.  
  585.         // Search type's resources
  586.         if(isset($resourcesDefinitions[$type])) foreach ($resourcesDefinitions[$type] as $subType=>$memVarName) {
  587.  
  588.             // filter on displayed resources
  589.             if($allowed && !isset($allowed[$type][strtolower($subType)])) continue;
  590.  
  591.             // remove deprecated
  592.             if(!($rData=rcGetResourceDefinition($type,$subType)) || isset($rData['deprecated']) || isset($rData['describer']['deprecated'])) continue;
  593.  
  594.             // Single instance resource: Browse all resources to see if this resource has already been created
  595.             if(@$rData['describer']['singleInstance']) {
  596.                 $found=0;
  597.                 foreach (WEnv::resConfigs() as $id=>$resConfig) if($resConfig->definition('type')==$type && $resConfig->definition('subType')==$subType){
  598.                     $found=1;
  599.                     break 2;
  600.                 }
  601.                 if($found) continue;
  602.             }
  603.  
  604.             // Set node
  605.             $tree['sub'][$type]['sub'][$subType]=array(
  606.                 'ico'=>$rData['resourceIconSmall'],
  607.                 'label'=>$rData['name'],
  608.                 'sub'=>array()
  609.             );
  610.             $nbSub++;
  611.             if(!isset($firstSelected)){
  612.                 $tree['sub'][$type]['sub'][$subType]['selected']=1;
  613.                 $firstSelected=1;
  614.             }
  615.  
  616.             // JS Array Data
  617.             $description[$type][$subType]=array($rData['name'],$rData['description'],$rData['resourcePreviewImage']);
  618.         }
  619.         // If no sub nodes, remove type-level node
  620.         if($nbSub==0) unset($tree['sub'][$type]);
  621.     }
  622.  
  623.     // Create treeView
  624.     $popupTreeView=new treeView('popupResTree');
  625.     $popupTreeView->phpTree=$tree;
  626.     $popupTreeView->selectFunction='popupSelectRes';
  627.     $popupTreeView->dblClickFunction='popupSelectAndValidateRes';
  628.  
  629.     // Create description JS array
  630.     $rd='';
  631.     foreach ($description as $type=>$stDesc){
  632.         $rd.=(($rd=='')?'{':',').'"'.$type.'":';
  633.         $st='';
  634.         foreach ($stDesc as $subType=>$desc){
  635.             $st.=(($st=='')?'{':',').'"'.$subType.'":';
  636.             $st.='Array("'.addslashes($desc[0]).'","'.addslashes($desc[1]).'","'.addslashes($desc[2]).'")';
  637.         }
  638.         $rd.=$st.'}';
  639.     }
  640.     $rd.='}';
  641.  
  642. ?>
  643. <script type="text/javascript">
  644. var resourcesDefinitions=<?php echo $rd;?>;
  645. var standalone=<?php echo (int)$standalone;?>;
  646. var resConfig,newResUseFilesList=0,selectedNode;
  647. function popupSelectRes(node){
  648.     var path=node.getPath().split('/');
  649.     if(path.length==2) {
  650.         node.toggleFold();
  651.         return;
  652.     }
  653.     node.setSelected();
  654.     selectedNode=node;
  655.  
  656.     resConfig={'newResType':path[1],'newResSubType':path[2]};
  657.  
  658.     var desc=resourcesDefinitions[path[1]][path[2]];
  659.     dgi('popupNewResDescTitle').innerHTML=desc[0];
  660.     dgi('popupNewResDescText').innerHTML=desc[1];
  661.     dgi('popupNewResDescImageDiv').innerHTML='<img id="resPreviewImg" style="width:266;height:200">';
  662.     var img=D.createElement('IMG'); img.src=desc[2]; //WA
  663.     dgi('resPreviewImg').src=desc[2]
  664.     wl.button.enable('step1Next');
  665. }
  666. function popupSelectAndValidateRes(node){
  667.     var path=node.getPath().split('/');
  668.     if(path.length==2) return;
  669.     resConfig={'newResType':path[1],'newResSubType':path[2]};
  670.     selectedNode=node;
  671.     step1Next();
  672. }
  673.  
  674. function step1Next(noBack){
  675.     if(noBack) dgi('step1Prev').style.display='none';
  676.     var e,li=(new wl.blockItemGroup('userBI')).getItems();
  677.     for(e in li) {
  678.         if(resConfig['newResType']!='administration') li[e].enable();
  679.         else if(li[e].n.alt!="userAdminControl") li[e].enable(0);
  680.     }
  681.  
  682.     dgi('stepLb').innerHTML=(noBack)?'':'(2/2)';
  683.     dgi('resourceName').value=selectedNode.getLabel()
  684.     dgi('step1Frame').style.display='none';
  685.     dgi('step2Frame').style.display='';
  686.     dgi('resourceName').select();
  687. }
  688.  
  689. function step2Prev(){
  690.     dgi('stepLb').innerHTML='(1/2)';
  691.     dgi('step1Frame').style.display='';
  692.     dgi('step2Frame').style.display='none';
  693. }
  694.  
  695. function popupValidate(){
  696.     // Add selected users
  697.     var i,u=D.getElementsByTagName('FIELDSET'),users='';
  698.     for(i=0;i<u.length;i++) if(u[i].getAttribute('name')=='userBI' && $(u[i]).e.className().has('biSel')) users+='/'+(u[i].id.substr(4));
  699.     if(users) wl.objectsAdd(resConfig,{'users':users.substr(1)});
  700.     wl.objectsAdd(resConfig,{'resourceName':dgi('resourceName').value});
  701.     if(newResUseFilesList) wl.objectsAdd(resConfig,{'useFilesList':1});
  702.  
  703.     if(standalone) wl.UICommand('close:newResource:'+wl.arrayPack(resConfig))
  704.     else {wl.asr.send(resConfig);popupHide();}
  705. }
  706. // Show step1 frame of new resource popup
  707. function newResPopupShow(shownNodes,useFilesList,inApp){
  708.     newResUseFilesList=useFilesList?1:0;
  709.     var n,typeNode,firstNode=0,ids,id,subType,tn,nbSubNodes=0;
  710.  
  711.     for(typeNode in treeViews['popupResTree'].tree['sub']){
  712.         n=new treeNode('popupResTree_top/'+typeNode);
  713.         if(shownNodes && !shownNodes[typeNode]) {
  714.             n.hideNode();
  715.         }
  716.         else {
  717.             n.showNode();
  718.  
  719.             if((shownNodes && typeof shownNodes[typeNode])=='object'){
  720.                 ids=n.childrenNodesIds();
  721.                 for(id in ids){
  722.                     subType=id.toLowerCase();
  723.                     if(!shownNodes[typeNode][subType]) {
  724.                         tn=(new treeNode(ids[id]))
  725.                         tn.hideNode()
  726.                     }
  727.                     else{
  728.                         tn=(new treeNode(ids[id]))
  729.                         tn.setSelected();
  730.                         selectedNode=tn
  731.                         if(!firstNode)    firstNode=tn;
  732.                         nbSubNodes++;
  733.                     }
  734.                 }
  735.             }
  736.             if(!firstNode)    firstNode=n.firstChild()
  737.         }
  738.     }
  739.     var pn=dgi('popupNewRes');
  740.     maskShow(0,1);
  741.     pn.style.visibility="hidden";
  742.     pn.style.display="";
  743.     maskMoveAbove(pn);
  744.     pn.style.visibility="";
  745.     pn.style.height="405px"; //XXX
  746.     <?php if(!$standalone) echo '$(pn).e.center();';?>
  747.  
  748.     // Single type/subtype: go to step2
  749.     if(nbSubNodes==1) {
  750.         popupSelectRes(firstNode)
  751.         step1Next(1);
  752.     }
  753.     else{
  754.         pn.focus()
  755.         D.onkeydown=popupKP;
  756.         popupSelectRes(firstNode)
  757.     }
  758. }
  759. function popupHide(){
  760.     if(standalone) wl.UICommand('close:')
  761.     maskHide(1);
  762.     dgi('popupNewRes').style.display="none";
  763.     D.onkeydown=null;
  764. }
  765. function popupKP(evt){if(!evt) evt=W.event;if(evt.keyCode==27) popupHide()}
  766. </script>
  767. <div id="popupNewRes" style="position:absolute;display:none">
  768. <?php
  769.     if($standalone){
  770.         $class='frame1';
  771.         $classL='frame2';
  772.         $classR='frame1';
  773.         $subClassR='frame3';
  774.     }
  775.     else {
  776.         outShadowBefore('700px');
  777.         $class='popup';
  778.         $classL=$classR='frame1';
  779.         $subClass2='frame2';
  780.     }
  781.  
  782.  
  783. ?>
  784. <div class="<?php echo $class;?>" style="padding:5px;width:690px">
  785. <?php
  786. echo '<div class="'.$class.'Header" style="font-size:150%">'.outImageIcon('new32').cfCaption('resNewResource').'<span id="stepLb" style="margin-left:2em">(1/2)</span></div>';
  787.  
  788.  
  789. /**
  790.  * 1st Step (resource type selection) frame
  791.  */
  792. ?>
  793. <div id="step1Frame" style="height:389px;overflow:hidden;padding:0px;margin:0px">
  794. <?php
  795. echo outTableTransparent(false,'table-layout:fixed');
  796. echo '<td style="width:220px" >';
  797.  
  798. // Resources tree
  799. echo $popupTreeView->HTML($classL,false,false,'height:379px;margin-top:0px;margin-bottom:0px');
  800.  
  801. // Detail frame
  802. ?>
  803. <td style="width:0.5em"></td><td style="position:relative;vertical-align:top">
  804. <div class="<?php echo $classR;?>" style="margin-bottom:0.5em;margin-top:0px">
  805. <div id="popupNewResDescTitle" style="font-weight:bold;margin:6px;margin-bottom:10px"> </div>
  806. <center style="margin-top:5px;margin-bottom:5px">
  807. <div id="popupNewResDescImageDiv">
  808.     <img alt="" src="/ext/image.php" style="width:266px;height:200px;margin:10px" onload="fade(this)">
  809. </div>
  810. <div class="<?php echo $subClassR;?>" id="popupNewResDescText" style="width:95%;text-align:justify;font-size:120% !important;font-size:80%;height:110px;overflow:auto"> </div>
  811. </center>
  812. </div>
  813. <table style="width:100%;margin-top:5px"><tr>
  814. <?php
  815.     // Cancel button
  816.     echo '<td>'.outButton(cfCaption('genCancel'),'javascript:popupHide()',outIcon('cancel'),false,false,'').'</td>';
  817.  
  818.     // Next button
  819.     echo '<td style="text-align:right">'.outButton(cfCaption('explorerNext'),'javascript:step1Next()',outIcon('next'),false,'step1Next','',false,true).'</td>';
  820. ?>
  821. </tr></table>
  822. </td></table>
  823. </div>
  824. <?php
  825.  
  826.  
  827. /**
  828.  * 2nd Step (resource name and groups selection) frame
  829.  */
  830. ?>
  831. <div id="step2Frame" style="height:389px;overflow:hidden;display:none;font-size:135%;padding-top:5px">
  832. <b style="font-size:74%"><?php echo cfCaption('newResourceChooseName');?></b><br>
  833. <input class="textInput" id="resourceName" style="width:80%;font-size:100%"><br>
  834. <br>
  835. <b style="font-size:74%"><?php echo cfCaption('newResourceSelectUsers');?></b><br>
  836. <div class="<?php echo $classL;?>" style="height:225px;overflow:auto;font-size:100%" id="usersFrame">
  837. <?php
  838. // Display users list
  839. foreach ($users as $id=>$user) if(!@$user['invisible']){
  840.     $out='<div style="float:left;margin-right:1em;padding:0px"><img src="'.cfExtGFX('/gfx/icons/'.$user['icon'],40,40).'" style="width:40px;height:40px;visibility:hidden" onload="fade(this)"></div>';
  841.     $out.=cfUTF8Encode($user['name']);
  842.     if(@$user['administrator']) $out.='<br><div class="warning smallFont">'.cfCaption('userAdministrator').'</div>';
  843.  
  844.     echo outBlockItem('userBI',$out,'alt="'.((@$user['administrator'])?'userAdminControl':'').'" id="user'.$user['id'].'"','width:210px;min-width:200px;padding:5px;overflow:hidden;text-overflow:ellipsis;cursor:pointer',array('type'=>'checkbox'));
  845. }
  846. ?>
  847. </div>
  848. <div class="extendedInfo" style="font-size:80%">
  849. <?php echo outImageIcon('info2').cfCaption('newResourceMayChange'); ?>
  850. </div>
  851. <table style="width:100%;margin-top:10px"><tr>
  852. <?php
  853. // Back button
  854. echo '<td>'.outButton('     '.cfCaption('explorerPrevious').'          ','javascript:step2Prev()',outIcon('backRed'),false,'step1Prev').'</td>';
  855. // Cancel button
  856. echo '<td style="text-align:center">'.outButton(cfCaption('genCancel'),'javascript:step2Prev();popupHide()',outIcon('cancel'),false,false).'</td>';
  857.  
  858. // Create button
  859. echo '<td style="text-align:right">'.outBt(cfCaption('adminResourceCreate'),outIcon('new'),'javascript:popupValidate()',false,false,'','up',100).'</td>';
  860. ?>
  861. </tr></table>
  862. </div>
  863. </div>
  864. <?php if(!$standalone) outShadowAfter(); ?>
  865. </div>
  866. <?php
  867. }
  868.  
  869.  
  870. /*
  871.  ***************************************************************************************************************************
  872.  * HTML / JS Output
  873.  ***************************************************************************************************************************
  874.  */
  875.  
  876. /**
  877.  * @desc Insert Javascript function needed for save button activation, and <form> with hidden fields
  878.  *         This function must be called before variables processing (rcProcessData)
  879.  *
  880.  */
  881. function rcInsertScriptAndForm(){
  882.     global $resourceData;
  883.     global $fileName;
  884.  
  885.     $isAdvancedConfig=!isset($resourceData['resourceFilename']);
  886.  
  887. // Javascript
  888. ?>
  889. <noscript>
  890. <div class="frame2" ><b class="warning"><?php echo outImage(outIcon('alertBig.png'),false,false,'float:left').cfCaption('loginErrorNoJavascript');?></b><br/><br/><br/></div><br/>
  891. </noscript>
  892. <script language="javascript" type="text/javascript">
  893. var buttonEnabled=0;
  894. function eSaveBt(dataName,dataValue){
  895.     if(window[dataName+"_changed"]) if(window[dataName+"_changed"](dataValue)=='cancel') return;
  896.     if(dataName=='name' && parent && parent.resourceNameModified) parent.resourceNameModified(dgn('resourceConfigFilename',0).value, dataValue);
  897.     if(W.dataChanged) {
  898.         if(dataChanged(dataName,dataValue)===false){
  899.             wl.button.disable('saveButton');
  900.             wl.button.enable('cancelButton');
  901.             buttonEnabled=1;
  902.             return;
  903.         }
  904.     }
  905.     if(!buttonEnabled){
  906.         wl.button.enable('cancelButton');
  907.         wl.button.enable('saveButton');
  908.         buttonEnabled=1;
  909.     }
  910.     <?php if(cfIsInApp()) echo 'save(1)';?>
  911. }
  912. function dataChangedNV(dataName){
  913.     var item=dgn(dataName);
  914.     if(!item) return;
  915.     if(item.type=='checkbox') dataValue=item.checked;
  916.     else if(item.type=='radio') {
  917.         var items=document.getElementsByName(dataName)
  918.         for(var i=0;i<items.length;i++) if(items[i].checked) dataValue=items[i].value;
  919.     }
  920.     else dataValue=item.value;
  921.  
  922.     if(W.dataChanged) dataChanged(dataName,dataValue);
  923. }
  924. function toggleAdvancedConfig(id,state){
  925.     dgi('cancelButton').className+=''; // IE WA
  926.     if(state=='doneUnfold'){
  927.         dgi('advancedConfigOuter').className='advancedConfigUnfolded';
  928.         dgi('advancedConfigUnfoldBt').style.display='none';
  929.         dgi('advancedConfigFoldBt').style.display='';
  930.         dgn("advancedConfig").checked=true;
  931.         save(1);
  932.     }
  933.     if(state=='doneFold'){
  934.         dgi('advancedConfigOuter').className='advancedConfigFolded';
  935.         dgi('advancedConfigUnfoldBt').style.display='';
  936.         dgi('advancedConfigFoldBt').style.display='none';
  937.         dgn("advancedConfig").checked=false;
  938.         save(1);
  939.     }
  940. }
  941.  
  942. // Save / apply changes
  943. function save(async,fromBt){
  944. <?php if(!$_ENV['buttonLessConfig']) echo 'if(!fromBt) return;';?>
  945.     if(async) asyncSubmitForm('configForm');
  946.     else{
  947.         for(e in dgn('configForm').getElementsByTagName('input')) {e=dgn('configForm').getElementsByTagName('input')[e] ;if(e.disabled) e.disabled=false};
  948.         for(e in dgn('configForm').getElementsByTagName('select')) {e=dgn('configForm').getElementsByTagName('select')[e] ;if(e.disabled) e.disabled=false};
  949.         document.configForm.submit()
  950.     }
  951. }
  952. <?php
  953.  
  954. /**
  955.  * User-configuration-only scripts (no advanced config)
  956.  */
  957. if(!$isAdvancedConfig){
  958. ?>
  959. // Bind user context menu
  960. function createUnboundUsersCM(unboundUsers){
  961.     var items=new Array(),i=0,e;
  962.     for(e in unboundUsers){
  963.         items[i]=ContextMenuItem(unboundUsers[e]["icon"],unboundUsers[e]["name"],"bindUser('"+e+"')");
  964.         i++;
  965.     }
  966.     ContextMenuAttach(dgi('showUnboundUsersBt'),items,{'align':'right','leftClick':1,'button':1,'style':{'width':130}})
  967. }
  968. // Bind user to resource (in app only)
  969. function bindUser(uid){
  970.     parent.toggleUser("<?php echo $resourceData['resourceFilename'];?>",uid);
  971. }
  972. // Unbind user from resource (in app only)
  973. function unbindUser(uid){
  974.     parent.toggleUser("<?php echo $resourceData['resourceFilename'];?>",uid);
  975. }
  976. // Show users panel and select user
  977. function UIShowUser(uid){wl.UICommand('showUser:'+uid)}
  978. <?php } ?>
  979. </script>
  980. <?php
  981.     // Insert
  982.     if(cfIsInApp() && !$isAdvancedConfig) echo '<div style="width:473px">';
  983.  
  984.     // cancel form
  985.     echo '<form action="'.$_SERVER['PHP_SELF'].'" method="GET" enctype="multipart/form-data" name="cancelForm" style="display:none">';
  986.         if(!cfIsInApp()) echo '<input type="hidden" name="config" value="'.$fileName.'">';
  987.         if(cfIsInApp()) echo '<input type="hidden" name="resourceConfigFilename" value="'.$fileName.'">';
  988.         echo '<input type="hidden" name="cancel" value="true">';
  989.     echo '</form>';
  990.     // Submit changes form
  991.     echo '<form id="configForm" name="configForm" action="'.$_SERVER['PHP_SELF'].'" method="POST" enctype="multipart/form-data" style="padding:0;margin:0">';
  992.     if(!cfIsInApp()) echo '<input type="hidden" name="config" value="'.$fileName.'">';
  993.     if(cfIsInApp()) echo '<input type="hidden" name="resourceConfigFilename" value="'.$fileName.'">';
  994.     echo '<input type="hidden" name="commandSent" value="modify">';
  995.     if(isset($_SESSION['activeResourceId'])) echo '<input type="hidden" name="resId" value="'.$_SESSION['activeResourceId'].'">';
  996. }
  997.  
  998. /**
  999.  * @desc Insert resource icon and name in configuration form
  1000.  *
  1001.  * @param array $resourceData
  1002.  */
  1003. function rcInsertIconName(&$resourceData){
  1004.     global $limitedConfig;
  1005.  
  1006.     $resourceDefinition=cfMGetVar('weezoResourceDefinition'.strtolower($resourceData['type'].$resourceData['subType']));
  1007.     // In application: show delete button, resource icon, resource modifiable name and resource type label
  1008.     if(cfIsInApp()){
  1009.         echo outButton(cfCaption('genDelete'),"javascript:parent.deleteResource('".$resourceData['resourceFilename']."')",outIcon('del'),false,false,'style="float:right"');
  1010.         echo outImage($resourceDefinition['resourceIcon'],false,false,'vertical-align:bottom;float:left;margin-right:1em');
  1011.         echo '<div style="margin-top:5px">';
  1012.         rcProcessData('name',dataText,$resourceData['name'],array(1,50),array('<span class="bigFont">'.cfCaption('resName').'</span>',36),false);
  1013.         echo '</div>';
  1014.         echo '<br>';
  1015.     }
  1016.     // Limited configuration
  1017.     elseif ($limitedConfig){
  1018.         echo '<div class="frame1Header">';
  1019.         echo outImage($resourceDefinition['resourceIconSmall'],false,'','vertical-align:middle;margin-right:1em');
  1020.         echo cfUTF8Encode($resourceData['name']);
  1021.         echo '</div>';
  1022.         return ;
  1023.     }
  1024.     // Remote administration
  1025.     else{
  1026.         echo outImage($resourceDefinition['resourceIcon'],false,'','vertical-align:middle;margin-right:1em');
  1027.         rcProcessData('name',dataText,$resourceData['name'],array(1,50),cfCaption('resName'));
  1028.     }
  1029.  
  1030.     $users=rcResourceGetUsers($resourceData['resourceFilename']);
  1031.     $allUsers=cfMGetVar('weezoUsers');
  1032.  
  1033.     echo '<div id="resourceUsersList" style="margin-bottom:10px">';
  1034.  
  1035.     // Generate linked users list
  1036.     $list='';
  1037.     foreach ($users as $id=>$user) {
  1038.         if(cfIsInApp()) {
  1039.             $list.=', <span style="text-decoration:underline" class="link" onclick="UIShowUser(\''.$user['id'].'\')">'.str_replace('<','<',str_replace('>','>',cfUTF8Encode($user['name']))).'</span>';
  1040.             $list.='(<img src="'.outIcon('cancelVSNarrow').'" style="cursor:hand;vertical-align:middle" onclick="javascript:unbindUser(\''.$id.'\')" title="'.str_replace('"',"''",cfCaption('genRemove')).'">)';
  1041.         }
  1042.         else{
  1043.             $list.=', <span>'.cfUTF8Encode($user['name']).'</span>';
  1044.         }
  1045.     }
  1046.  
  1047.     if($list) {
  1048.         $out='<div class="extendedInfo">';
  1049.         $out.='<span style="width:80%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">';
  1050.         $out.=outImageIcon('info2').'<b>'.cfCaption('resSharedWith').cfCaption('genSeparator').'</b>'.substr($list,1);
  1051.     }
  1052.     else {
  1053.         $out='<div class="extendedWarning">';
  1054.         $out.='<span style="width:80%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'.outImageIcon('warning').cfCaption('resSharedWithNone');
  1055.     }
  1056.     $out.='</span>'; // End of overflow hidden
  1057.  
  1058.     // List unbound users (in-app only)
  1059.     $unbound='';
  1060.     if(cfIsInApp() && count($users)<count($allUsers)) foreach ($allUsers as $id=>$user) {
  1061.         // if not already bound, and not "system" user
  1062.         if(!isset($users[$id]) && !@$user['invisible'] &&
  1063.         // and not admin resource or user is admin
  1064.            ($resourceData['type']!=='administration' || @$user['administrator'])){
  1065.             $unbound.=',"'.$user['id'].'":{"name":"'.str_replace('"','"',cfUTF8Encode($user['name'])).'","icon":"'.(cfExtGFX('/gfx/icons/'.$user['icon'],16,16)).'"}';
  1066.         }
  1067.     }
  1068.  
  1069.     // Bind new user control (in-app only)
  1070.     if($unbound){
  1071.         $out.='<span class="link" style="position:absolute;right:5px" id="showUnboundUsersBt">'.cfCaption('genAdd').outImage(outIcon('down'),false,false,'vertical-align:bottom"').'</span>';
  1072.         $unbound='createUnboundUsersCM(unboundUsers={'.substr($unbound,1).'});';
  1073.     }
  1074.  
  1075.     $out.='</div>'; // end of extendedInfo/warning
  1076.  
  1077.     // Async response (in-app only, as in remote admin, output is buffered using ob_XXX and injected into a div
  1078.     if(cfIsAsync() && cfIsInApp()) {
  1079.         rcAddAsyncResponse(cfAsyncXMLInnerHTMLbyId($out,'resourceUsersList'));
  1080.         if($unbound) rcAddAsyncResponse(cfAsyncXMLJSaction($unbound));
  1081.     }
  1082.     // Sync display
  1083.     else {
  1084.         echo $out;
  1085.         if($unbound) echo '<script type="text/javascript">'.$unbound.'</script>';
  1086.     }
  1087.     echo '</div>';
  1088. }
  1089.  
  1090. /**
  1091.  * @desc Included into config script of resources requiring MySQL: if MySQL not installed, echo error message and return false
  1092.  *
  1093.  * @return boolean: false if MySQL not installed, true if installed
  1094.  */
  1095. function rcMySQLCheckInstalled(){
  1096.     if(cfMySQLInstalled()) return true;
  1097.  
  1098.     echo '<br><br><div class="extendedWarning"><br>';
  1099.     echo outImage(outIcon('warning'),false,false,'float:left');
  1100.     echo '<center>'.cfCaption('extMySQLRequired').'<br><br>';
  1101.     echo outButton(cfCaption('resMisc').'...',"javascript:wl.UICommand('pluginmanagement')",outIcon('plugins'));
  1102.     echo '</center> </div>';
  1103.     return false;
  1104. }
  1105.  
  1106. /**
  1107.  * @desc Insert Folder / files list selection sub-form
  1108.  *
  1109.  * @param array $fileTypeFilter: array of mime types included, false for no filter
  1110.  * @param string $defaultDirectory: default shared directory, false to use cfAppSharedDir()
  1111.  * @param array $options:
  1112.  *             'noDiv'=>1 : do not include outer div
  1113.  *             'noSubDir'=>1 : do not include sub directories
  1114.  */
  1115. function rcSharedFilesBox($fileTypeFilter=false, $defaultDirectory=false, $options=false){
  1116.     global $limitedConfig;
  1117.     global $resourceData;
  1118.  
  1119.     if($limitedConfig) return;
  1120.  
  1121.     // Filter (audio/video/image)
  1122.     if($fileTypeFilter) {
  1123.         $fileTypeFilter=cfArrayValuesToKeys($fileTypeFilter);
  1124.         require_once(INCLUDE_DIR.'mime_type.php');
  1125.         foreach ($fileTypeFilter as $ftf){
  1126.             foreach ($_ENV['weezoMime'] as $ext=>$mime) if(cfCmpLeft($mime,$ftf)) $extFilterArray[$ext]=$ext;
  1127.         }
  1128.         $extFilter='*.'.implode(';*.',$extFilterArray);
  1129.     }
  1130.     else $extFilter='';
  1131.  
  1132.     // Backward compatibility: set sharedMode to folder for previously created resources
  1133.     if(!isset($resourceData['sharedMode'])) {if(isset($resourceData['path'])) $resourceData['sharedMode']='folder'; else $resourceData['sharedMode']='list';}
  1134.  
  1135.     if(!isset($options['noDiv'])) echo outDivFrame('frame2');
  1136.  
  1137.     /**
  1138.      * Share mode selection
  1139.      */
  1140.     echo '<div class="frame2Header">'.outTableTransparent('frame2Header').'<tr><td>';
  1141.     echo cfCaption('genFiles').cfCaption('genSeparator').'</td><td>';
  1142.     rcProcessData('sharedMode',dataList,'list',array('folder','list'),array(
  1143.         array(false,'folder',array(outIcon('folder'),cfCaption('sharedFolder').'</td><td>')),
  1144.         array(false,'list',array(outIcon('filesList'),cfCaption('sharedFilesList')))
  1145.         ));
  1146.     echo '</td></tr></table></div>';
  1147.  
  1148.     /**
  1149.      * Shared Folder
  1150.      */
  1151.     echo '<div class="frame3" id="sharedModeFolder"'.(($resourceData['sharedMode']==='list')?' style="display:none"':'').'>';
  1152.  
  1153.     // Base folder
  1154.     rcProcessData('path',dataFolderPath,(($defaultDirectory)?$defaultDirectory:cfAppSharedDir()),((isset($options['noComputerRoot']))?'noComputerRoot':false),true);
  1155.  
  1156.     // Subdirectories included
  1157.     if(!isset($options['noSubDir'])) rcProcessData('subFoldersIncluded',dataBoolean,true,false,cfCaption('explorerCfgSubDirectoriesIncluded'));
  1158.     echo '</div>';
  1159.  
  1160.     /**
  1161.      * List of files/folders
  1162.      */
  1163.     echo '<div id="sharedModeList"'.(($resourceData['sharedMode']==='folder')?' style="display:none"':'').'>';
  1164.  
  1165.     // shared items, | separated
  1166.     if(!isset($resourceData['sharedItems'])) $resourceData['sharedItems']=false;
  1167.     if($resourceData['sharedMode']=='folder') $_POST['sharedItems']=$resourceData['sharedItems']; // Prevent list modification if sharedMode is folder
  1168.     // Hidden control containing items list, | separated
  1169.     echo '<div style="position:absolute;top:-1000px">';    rcProcessData('sharedItems',dataText,'',false,' ');    echo '</div>';
  1170.  
  1171.     if($resourceData['sharedMode']=='list'){
  1172.         require_once(INCLUDE_DIR.'explorerFunctions.php');
  1173.         $out=''; $str='';$dir=array();$file=array();
  1174.         // Generate HTML list from string
  1175.         foreach (explode('|',$resourceData['sharedItems']) as $cfn){
  1176.             if(cfFileExtension($cfn)=='lnk') $cfn=cfShortcutResolve($cfn);
  1177.             if(is_dir($cfn)) $dir[$cfn]=efIcon($cfn);
  1178.             elseif(file_exists($cfn)) {
  1179.                 // Apply filter (images, audio, video)
  1180.                 if($fileTypeFilter && !isset($fileTypeFilter[efFileType($cfn)])) continue;
  1181.                 $file[$cfn]=efIcon($cfn);
  1182.             }
  1183.         }
  1184.         // list item html
  1185.         function li($cfn,$ico){
  1186.             static $nb=0;
  1187.             if(!$cfn) return '<div class="'.((($nb++)%2)?'odd':'even').'"> </div>';
  1188.             if(!cfIsInApp()) return '<div class="'.((($nb++)%2)?'odd':'even').'" id="'.cfUTF8Encode($cfn).'">'.outImage($ico,false,'class="ico2"').'<span onmouseover="tmp=lTt(this);tooltip(this,tmp)">'.cfUTF8Encode(basename($cfn)).'</span><br clear="all"></div>';
  1189.             return '<div class="'.((($nb++)%2)?'odd':'even').'" id="'.cfUTF8Encode($cfn).'">'.outButtonSmall(false,'javascript:filesRemove(this)',outIcon('eraser'),cfCaption('genRemove'),false,'style="float:right"').outImage($ico,false,'class="ico2"').'<span onmouseover="tooltip(this,lTt(this))">'.cfUTF8Encode(basename($cfn)).'</span><br clear="all"></div>';
  1190.         }
  1191.         $nb=0;
  1192.  
  1193.         // Add dirs
  1194.         foreach ($dir as $cfn=>$ico) {
  1195.             $out.=li($cfn,$ico);
  1196.             $str.='|'.$cfn;
  1197.             $nb++;
  1198.         }
  1199.         // Add files
  1200.         foreach ($file as $cfn=>$ico) {
  1201.             $out.=li($cfn,$ico);
  1202.             $str.='|'.$cfn;
  1203.             $nb++;
  1204.         }
  1205.         while($nb++<7) $out.=li(false,false);
  1206.         $resourceData['sharedItems']=substr($str,1);
  1207.     }
  1208.  
  1209.     // Shared files & folders (drag & drop) box
  1210.     echo '<div class="frame3 lvDiv" id="sharedItemsDropBox" style="position:relative;height:160px;overflow:auto;display:block">';
  1211.  
  1212.     // files & folder list
  1213.     if(isset($out)){
  1214.         if(cfIsAsync() && cfIsInApp()) {
  1215.             rcAddAsyncResponse(cfAsyncXMLInnerHTMLbyId($out.'<center style="position:absolute;top:0;width:100%;padding-left:15%;padding-right:15%;padding-top:55px" class="watermark">'.cfCaption('dropFilesHere').'</center>','sharedItemsDropBox'));
  1216.             //rcAddAsyncResponse(cfAsyncXMLJSaction('scrollBottom();'));
  1217.         }
  1218.         else echo $out;
  1219.     }
  1220.      if(cfIsInApp()) echo '<center style="position:absolute;width:100%;top:0;padding-left:15%;padding-right:15%;padding-top:55px" class="watermark">'.cfCaption('dropFilesHere').'</center>';
  1221.  
  1222.     echo '</div>';
  1223.  
  1224.     // Drag & Drop and files&folders input box management
  1225.     echo '<input name="dropFileInput" style="display:none" onkeyup="filesDropped()"><input type="button" name="dropFileButton" onclick="filesDropped()" style="display:none">';
  1226.  
  1227.     // Add & clear all buttons (only in application UI)
  1228.     if(cfIsInApp()){
  1229.         // Add files & folders button
  1230.         echo '<table style="width:100%"><tr><td>';
  1231.         echo outButton(cfCaption('addFiles'),"javascript:wl.UICommand('openFiles:".$extFilter."','dropFileInput')",outIcon('addMult'),false,false);
  1232.  
  1233.         // Clear all files button
  1234.         echo '</td><td style="text-align:right">'.outButton(cfCaption('explorerClearAll'),'javascript:filesClearList()',outIcon('eraser'),false,false).'</td></tr></table>';
  1235.     }
  1236.     echo '</div>'; // #sharedModeList
  1237. ?>
  1238. <script type="text/javascript">
  1239. var sharedMode="<?php echo $resourceData['sharedMode'];?>";
  1240. var extFilter=<?php if($extFilterArray) echo '{"'.implode('":1,"',$extFilterArray).'":1}'; else echo 'false';    ?>;
  1241. function scrollBottom(){dgi("sharedItemsDropBox").scrollTop=dgi("sharedItemsDropBox").scrollHeight}
  1242. function basename(cfn){
  1243.     if(cfn.lastIndexOf('/')==cfn.length-1) cfn=cfn.substr(0,cfn.length-1);
  1244.     return cfn.substr(cfn.lastIndexOf('/')+1);
  1245. }
  1246.  
  1247. function sharedMode_changed(val){
  1248.     if(val=='folder') {
  1249.         dgi('sharedModeList').style.display='none';
  1250.         dgi('sharedModeFolder').style.display=''
  1251.         D.getElementsByName('sharedMode')[1].checked=false //WA
  1252.     }
  1253.     else {
  1254.         dgi('sharedModeFolder').style.display='none';
  1255.         dgi('sharedModeList').style.display=''
  1256.         D.getElementsByName('sharedMode')[0].checked=false //WA
  1257.     }
  1258.     sharedMode=val;
  1259.  
  1260.     //IE bug WA
  1261.     if(dgi("advancedConfigDiv")) {
  1262.         with(dgi("advancedConfigDiv").style){overflow=(overflow=='hidden')?'':'hidden';    overflow=(overflow=='hidden')?'':'hidden';}
  1263.     }
  1264. }
  1265. function filesDropped(){
  1266.     var items=dgn('dropFileInput').value;dgn('dropFileInput').value='';
  1267.     if(dgi('sharedModeList').style.display!='none')    filesAdd(items);
  1268. }
  1269. function filesClearList(){
  1270.     <?php
  1271.     if(!cfIsInApp()) echo 'dgi("sharedItemsDropBox").innerHTML="";';
  1272.     else{
  1273.         ?>
  1274.     dgi('sharedItemsDropBox').innerHTML='<center style="position:absolute;width:100%;top:0;padding-left:15%;padding-right:15%;padding-top:75px" class="watermark"><?php echo cfCaption('dropFilesHere');?></center>';
  1275.         <?php
  1276.     }
  1277.     ?>
  1278.     fillEmpty();
  1279.     dgn('sharedItems').value='';
  1280.     if(W.save) save(1);
  1281.     if(W.rcSharedFilesBoxUpdated) rcSharedFilesBoxUpdated('');
  1282. }
  1283.  
  1284. function filesAdd(str){
  1285.     if(!str) return;
  1286.  
  1287.     var items=str.replace(/\\/g,'/').split('|');
  1288.  
  1289.     var prevItems=dgn('sharedItems').value;
  1290.     if(!prevItems) prevItems=new Array(); else prevItems=prevItems.split('|');
  1291.  
  1292.     var pIL={}, output='',ext;
  1293.  
  1294.     for(var i=0;i<prevItems.length;i++) pIL[basename(prevItems[i])]=prevItems[i];
  1295.     for(var i=0;i<items.length;i++) {
  1296.         if(!pIL[basename(items[i])]) {
  1297.             if(extFilter){
  1298.                 ext=items[i].substr(items[i].lastIndexOf('.')+1).toLowerCase();
  1299.                 // if dir or allowed extension, add
  1300.                 if(items[i].lastIndexOf('.')<=items[i].lastIndexOf('/') || extFilter[ext]) pIL[basename(items[i])]=items[i];
  1301.             }
  1302.             else pIL[basename(items[i])]=items[i];
  1303.         }
  1304.     }
  1305.  
  1306.     items=''; for(var e in pIL) items+='|'+pIL[e]; dgn('sharedItems').value=items.substr(1);
  1307.     scrollBottom();
  1308.     if(W.save) save(1); else filesOfflineUpdate(pIL)
  1309.     if(W.rcSharedFilesBoxUpdated) rcSharedFilesBoxUpdated(dgn('sharedItems').value);
  1310. }
  1311. var filesRemoveTO=0;
  1312. function filesRemove(n){
  1313.     if(filesRemoveTO) clearTimeout(filesRemoveTO); filesRemoveTO=0;
  1314.     n=n.parentNode; cfn=n.id;
  1315.     var n2=n.nextSibling;
  1316.     n.parentNode.removeChild(n);
  1317.     while(n2){
  1318.         if(n2.className=='odd') n2.className='even';
  1319.         else if(n2.className=='even') n2.className='odd';
  1320.         else break;
  1321.         n2=n2.nextSibling;
  1322.     }
  1323.     var items='',prevItems=dgn('sharedItems').value;
  1324.     if(!prevItems) prevItems=new Array(); else prevItems=prevItems.split('|');
  1325.     for(var i=0;i<prevItems.length;i++) if(prevItems[i]!=cfn) items+='|'+prevItems[i];
  1326.     dgn('sharedItems').value=items.substr(1);
  1327.     filesRemoveTO=setTimeout("save(1)",1500);
  1328.     fillEmpty();
  1329.     if(W.rcSharedFilesBoxUpdated) rcSharedFilesBoxUpdated(dgn('sharedItems').value);
  1330. }
  1331. function fillEmpty(){
  1332.     var n=dgi("sharedItemsDropBox").firstChild;
  1333.     var nb=0;
  1334.     while(1){
  1335.         if(n.className=='odd'||n.className=='even') nb++;
  1336.         if(!(n=n.nextSibling)) break;
  1337.     }
  1338.     var out='';
  1339.     while(nb++<8) out+='<div class="'+((nb%2)?'even':'odd')+'"> </div>';
  1340.     html=dgi("sharedItemsDropBox").innerHTML;
  1341.     var p=html.toLowerCase().indexOf('<center');
  1342.     dgi("sharedItemsDropBox").innerHTML=html.substr(0,p)+out+html.substr(p);
  1343. }
  1344. function lTt(n){return '<span style="white-space:nowrap">'+n.parentNode.id+'</span>'}
  1345. function filesOfflineUpdate(items){
  1346.     var item,o='',nb=0;
  1347.     var WM=dgi("sharedItemsDropBox").innerHTML;
  1348.     WM=WM.substr(WM.indexOf('<CENTER'));
  1349.     for(var i in items){
  1350.         item=items[i];
  1351.         o+='<div class="'+((nb%2)?'odd':'even')+'">'+item+'</div>';
  1352.         nb++;
  1353.     }
  1354.     while(nb<8) {
  1355.         o+='<div class="'+((nb%2)?'odd':'even')+'"> </div>';
  1356.         nb++;
  1357.     }
  1358.     dgi("sharedItemsDropBox").innerHTML=o+WM;
  1359. }
  1360.  
  1361. </script>
  1362. <?php
  1363. if(!isset($options['noDiv'])) echo '</div>';
  1364. }
  1365.  
  1366. /**
  1367.  * @desc Insert HTML stuff for start of advanced configuration (folded or unfolded depending on $resourceData['advancedConfig'] value)
  1368.  *
  1369.  */
  1370. function rcAdvancedConfigStart(){
  1371.     global $resourceData;
  1372.     global $limitedConfig;
  1373.  
  1374.     $_ENV['advancedConfig']=1;
  1375.  
  1376.     // Backward compatibility : set advanced as default for already configured resources
  1377.     if(!isset($resourceData['advancedConfig'])){
  1378.         if(isset($resourceData['resourceConfigured'])) $resourceData['advancedConfig']=true; else $resourceData['advancedConfig']=false;
  1379.     }
  1380.  
  1381.     echo '<span style="display:none">';
  1382.     rcProcessData('advancedConfig',dataBoolean,false,false,'lc',false);
  1383.     echo '</span>';
  1384.     if(!$limitedConfig && $resourceData['advancedConfig']==false) $folded=true; else $folded=false;
  1385.     echo outDivFrame("advancedConfig".(($folded)?'Folded':'Unfolded'),'id="advancedConfigOuter"');
  1386.     echo '<div class="advancedConfigToggleBt" id="advancedConfigUnfoldBt" onclick="wl.nodeCollapseToggle(\'advancedConfigDiv\',false,\'toggleAdvancedConfig\')" '.(($folded)?'':'style="display:none"').'>'.cfCaption('configAdvanced').outimage(outIcon('advancedConfigFold'),false,false,'vertical-align:middle').'</div>';
  1387.     echo '<div class="advancedConfigToggleBt" id="advancedConfigFoldBt" onclick="wl.nodeCollapseToggle(\'advancedConfigDiv\',false,\'toggleAdvancedConfig\')" '.(($folded)?'style="display:none"':'').'>'.cfCaption('configAdvanced').outimage(outIcon('advancedConfigUnfold'),false,false,'vertical-align:middle').'</div>';
  1388.  
  1389.     echo outCollapsableFrame('advancedConfigDiv',false,false,$folded);
  1390. }
  1391.  
  1392. /**
  1393.  * @desc Close advanced config divs
  1394.  *
  1395.  */
  1396. function rcAdvancedConfigEnd(){
  1397.     if(!isset($_ENV['advancedConfig'])) return ;
  1398.     unset($_ENV['advancedConfig']);
  1399.     echo "</div></div>\n";
  1400. }
  1401.  
  1402. /**
  1403.  * @desc Insert configuration buttons to plugin's administration page, for use in application config tab
  1404.  *
  1405.  * @param string $path: path from resource root dir to config script
  1406.  */
  1407. function rcPluginConfigurationButtons($path){
  1408.     global $resourceData;
  1409.  
  1410.     if(!cfIsInApp()) return;
  1411.  
  1412.     if($path[0]!='/') $path='/'.$path;
  1413.     $extraPath=((strpos($path,'?')===false)?'?':'&').'weezoKey='.$_SESSION['weezoKey'];
  1414.  
  1415.     // Resource administration button
  1416.     echo '<div style="position:absolute;top:50%;left:0;width:99%;text-align:center">';
  1417.     echo outButton(cfCaption('genConfigure'),'/res/'.$resourceData['type'].'/'.$resourceData['subType'].$path,outIcon('gears'));
  1418.     echo '   ';
  1419.     echo outButton(cfCaption('genConfigure').' ('.cfCaption('musicPopupPlayer').')','/res/'.$resourceData['type'].'/'.$resourceData['subType'].$path.$extraPath,outIcon('separateWindow'),false,false,' target="_blank"');
  1420.     echo '</div>';
  1421. }
  1422.  
  1423. /**
  1424.  * @return string : HTML code
  1425.  * @desc return HTML code for theme selection, and theme preview link.
  1426.  * Must be inserted in resource parameters form, returned (POST...) value is named 'theme'
  1427. */
  1428. function rcThemeSelectionControl($theme=false){
  1429.     global $resourceData;
  1430.  
  1431.     // No possible selection for single-theme browsers
  1432.     if(cfBGetVar('theme')) return;
  1433.  
  1434.     $dir=cfAppDocRoot().'/themes';
  1435.     if(!$theme){
  1436.         // Default value
  1437.         if(!isset($resourceData['theme'])) $resourceData['theme']='noTheme';
  1438.         // Process POST command
  1439.         if(isset($_POST['theme'])) $resourceData['theme']=cfUTF8Decode($_POST['theme']);
  1440.         // Set Theme
  1441.         $defaultTheme=$resourceData['theme'];
  1442.     }
  1443.     else $defaultTheme=$theme;
  1444.     // Display control
  1445.     $output = '<span style="margin-right:1em;">'.cfCaption('genTheme').'</span>';
  1446.     $output .= '<select class="textInput" name="theme" id="themeSelect" size="1" style="width:15em;margin-right:1em;" '.(($theme)?'':'onChange="eSaveBt(\'theme\',this.value)"').'>';
  1447.     // Display "no theme" item (only if $theme parameter is not set)
  1448.     if(!$theme){
  1449.         if($defaultTheme!='noTheme') $output .= '<option value="noTheme">'.cfCaption('adminNoTheme').'</option>';
  1450.         else $output .= '<option selected value="noTheme">'.cfCaption('adminNoTheme').'</option>';
  1451.     }
  1452.  
  1453.     // Create themes select items
  1454.     $themes=cfMGetVar('weezoThemes');
  1455.  
  1456.     foreach ($themes as $name=>$data) if($name!='skins/default' && !isset($data['private'])){
  1457.         if($name==$defaultTheme) $output .= '<option selected value="'.cfUTF8Encode($name).'">'.cfUTF8Encode($name).'</option>'; else $output .= '<option value="'.cfUTF8Encode($name).'">'.cfUTF8Encode($name).'</option>';
  1458.     }
  1459.     $output .= '</select>';
  1460.     //$output .= outButton(cfCaption('genPreview'),'javascript:window.open(\'/themes/themePreview.php?theme=\' + document.getElementById(\'themeSelect\').value,\'Window\',\'width=600,height=460\');generateError;',outIcon('preview'));
  1461.     return $output;
  1462.  }
  1463.  
  1464. /**
  1465.   * output a save and a cancel buttons dedicated to config.php scripts
  1466.   *
  1467.   * @return string : HTML code
  1468.   * @param boolean $defaultCancelEnabled : set to true to enable cancel button, false to set it as disabled at page load
  1469.   */
  1470. function rcButtonSaveCancel($defaultCancelEnabled=false){
  1471.     global $limitedConfig;
  1472.  
  1473.     //Close advanced config divs
  1474.     if(isset($_ENV['advancedConfig'])) echo "</div></div>\n";
  1475.  
  1476.     $output='<center style="margin-top:0.3em'.(($_ENV['buttonLessConfig'])?';display:none':'').'">';
  1477.     // Save/apply button
  1478.     if((!cfIsInApp()) && basename($_SERVER['PHP_SELF'])=='index.php') $applyScript='save(1,1)'; // Remote configuration environment
  1479.  
  1480.     // Limited configuration environment or application environment
  1481.     // note: re-enable all input and select items in order to transmit them on form submition
  1482.     else $applyScript='save(0,1)';
  1483.  
  1484.     // Save/commit button
  1485.     $output.=outButtonDisabled(cfCaption('genSave'),'javascript:'.$applyScript,outIcon('save'),false,'saveButton','style="margin-right:5em"');
  1486.  
  1487.     // Browser environment: cancel close window (limited config) or reload page (remote administration)
  1488.     if(!cfIsInApp())
  1489.         $output .= outButton(cfCaption('genCancel'),(($limitedConfig)?'javascript:if(winMe) winMe.closeMe(); else window.close()':'javascript:reloadForm.submit()'),outIcon('cancel'),false,'cancelButton');
  1490.     // App: use cancelForm to reset page
  1491.     else {
  1492.         $output.=outButton(cfCaption('genCancel'),'javascript:D.cancelForm.submit();',outIcon('cancel'),false,'cancelButton',false,false,!$defaultCancelEnabled);
  1493.     }
  1494.     $output .= '</center></form>';
  1495.     if(!cfIsAsync()) echo cfDragRegisterItems('');
  1496.     return $output;
  1497. }
  1498.  
  1499. /**
  1500.  * @desc Load data required for "limited configuration" (ie inline configuration by end-user), and display page's head and script
  1501.  *
  1502.  */
  1503. function rcInitLimitedConfig(){
  1504.     global $resourceData;
  1505.     // Load current resource data into $resourceData used by config scripts
  1506.     $resourceData=cfRGetVar();
  1507.  
  1508.     $_ENV['buttonLessConfig']=false;
  1509.  
  1510.     // Insert page's head
  1511.     $_ENV['winCloseURL']='/res/'.cfRGetVar('type').'/'.cfRGetVar('subType').'/'.cfRGetVar('baseFile'); // Frameless close URL
  1512.     cfInsertHEAD(false);
  1513.     if(cfBGetVar('name')=='iPhone') echo '<meta name="viewport" content="width=device-width, user-scalable=1">';
  1514.     ?>
  1515.     <script type="text/javascript">
  1516.     function applyChanges(){
  1517.         if(parent.win(winMe.getOpenerId())) parent.win(winMe.getOpenerId()).reload();
  1518.         winMe.closeMe();
  1519.     }
  1520.     function keydown(e){
  1521.         if(e && e.which==27) winMe.closeMe();
  1522.         else if(window.event && window.event.keyCode==27) winMe.closeMe();
  1523.     }
  1524.     document.onkeydown=keydown;
  1525.     </script>
  1526.     <body onload="onLoadFunc()">
  1527.     <?php
  1528.     echo cfScriptLink('wz_dragdrop.js');
  1529.     echo outDivFrame('frame1','id="limitedConfigFrame"',cfGetBrowser()=='ie'?'width:99%':'');
  1530. }
  1531.  
  1532. /**
  1533.  * @desc Return HTML code for a resource (config) item
  1534.  *
  1535.  * @param string $rid: id of resource
  1536.  * @param WUserConfig $uc: bound user config, if set, display all controls, else just display selectable resource
  1537.  * @return string
  1538.  */
  1539. function rcResourceBlock($rid,$uc=false){
  1540.     $r=cfMGetVar('weezoResData'.$rid);
  1541.     $o='';
  1542.     // Icon
  1543.     $o.=outImage($r['definition']['resourceIcon'],false,false,'float:left;margin-right:0.5em');
  1544.  
  1545.     // Name
  1546.     $o.='<div class="uiUsersResTitle">'.cfUTF8Encode($r['name']).'</div>';
  1547.  
  1548.     $o.='<div class="uiUsersResL2">'.cfUTF8Encode(@$r['definition']['resourceTypeLabel']).'</div>';
  1549.     $o.='<div class="uiUsersResL3">';
  1550.     $st=$r['subType'];
  1551.     switch ($r['type']){
  1552.         case 'explorer':
  1553.             if(@$r['sharedMode']=='folder') $o.=cfUTF8Encode($r['path']);
  1554.             elseif(@$r['sharedMode']=='list') $o.=cfCaption('sharedFilesList');
  1555.             break;
  1556.         case 'bookmarks':
  1557.             if($st=='std' ||$st=='mosaic'){
  1558.                 if(@$r['bookmarksType']=='Opera') $o.='Opera';
  1559.                 elseif(@$r['bookmarksType']=='Firefox') $o.='Firefox';
  1560.                 elseif(@$r['bookmarksType']=='IE') $o.='Internet Explorer';
  1561.                 else $o.=cfCaption('bookmarksCustom');
  1562.             }
  1563.             break;
  1564.         case 'website':
  1565.             if($st=='external') $o.=cfRGetVar('url');
  1566.             if($st=='html') $o.=cfUTF8Encode(basename(cfRGetVar('path')));
  1567.             break;
  1568.     }
  1569.     $o.='</div>';
  1570.  
  1571.     // UI users tab: include controls
  1572.     if($uc){
  1573.         $nb=count($uc->getResources());
  1574.         $i=0;
  1575.         $pos=0;
  1576.         foreach ($uc->getResources() as $id=>$res){
  1577.             if($id==$rid) $pos=$i;
  1578.             $i++;
  1579.         }
  1580.  
  1581.         // Resource actually displayed at login page
  1582.         if($uc->getVar('displayResourceAtLogin')==$rid) $o.='<div style="position:absolute;left:3px;top:3px" '.outToolTip('<span style=\'text-decoration:line-through\'>'.cfCaption('userUseMainpage').'</span>').' onclick="uiUsersResLogin()">'.outImage(outIcon('sel'),false,'onmouseover="this.src=\''.outIcon('selCancel').'\'" onmouseout="this.src=\''.outIcon('sel').'\'"').'</div>';
  1583.  
  1584.         // Remove control
  1585.         $o.=outImage(outIcon('cancelVS12'),'javascript:uiUsersResDel(\''.$rid.'\')',outToolTip(cfCaption('genRemove')), 'position:absolute;right:3px;top:3px');
  1586.         // Set as displayed at login page
  1587.         if($uc->getVar('displayResourceAtLogin')!=$rid) $o.=outImage(outIcon('selectedVS'),'javascript:uiUsersResLogin(\''.$rid.'\')',outToolTip(cfCaption('userUseMainpage')), 'position:absolute;right:3px;bottom:3px');
  1588.         // Up
  1589.         if($pos>0) $o.=outImage(outIcon('up'),'javascript:uiUsersResUp(\''.$rid.'\')',outToolTip(cfCaption('genUp')), 'position:absolute;left:8px;top:26px');
  1590.         // Down
  1591.         if($pos<$nb-1) $o.=outImage(outIcon('down'),'javascript:uiUsersResDown(\''.$rid.'\')',outToolTip(cfCaption('genDown')), 'position:absolute;left:20px;top:26px');
  1592.  
  1593.         // a single res may be selected
  1594.         $opt=array();
  1595.         // ondblclick function: configure resource
  1596.         $onclick=" ondblclick=\"wl.UICommand('showResource:".$rid."')\"";
  1597.     }
  1598.     else {
  1599.  
  1600.  
  1601.         // Multiple res may be selected
  1602.         $opt=array('type'=>'checkbox');
  1603.         // onclick function
  1604.         $onclick=' onmousedown="toggleRes(\''.$rid.'\')" ondblclick="selectRes(\''.$rid.'\')"';
  1605.     }
  1606.  
  1607.  
  1608.     return outBlockItem('uiUsers',$o,'id="uiUsersResBlock_'.$rid.'"'.$onclick,'padding:5px;width:170px;text-align:left;margin:2px;margin-right:0px;margin-left:4px',$opt);
  1609. }
  1610.  
  1611. /*
  1612.  ***************************************************************************************************************************
  1613.  * Main parameter processing / display
  1614.  ***************************************************************************************************************************
  1615.  */
  1616.  
  1617.  
  1618. /**
  1619.  * @desc insert an image and / or a caption depending on $controlDefinitionArray definition
  1620.  *
  1621.  * @param array $controlDefinitionArray
  1622.  *            $controlDefinitionArray is a one or two elements array of image or caption definition (icd)
  1623.  *            (if $controlDefinitionArray is a string then it is treated as a one-element array)
  1624.  *            - if icd is false, don't display anything
  1625.  *            - if documentRoot/icd or resource's directory/icd is an image, display this image
  1626.  *            - else display icd as a caption
  1627.  *
  1628.  * @param alignLabelControl or alignControlLabel $align : defines wether control is located right or left of caption/image
  1629.  *            use this parameter to insert right or left margins
  1630.  * @return unknown
  1631.  */
  1632. function rcDisplayLabelAndOrImage($controlDefinitionArray,$align){
  1633.     global $resourceData;
  1634.  
  1635.     if($align==alignLabelControl) $alignStyle="margin-right:0.3em;"; else $alignStyle="margin-left:0.3em;";
  1636.     $alignStyle.='cursor:pointer;vertical-align:middle';
  1637.  
  1638.     // Check $controlDefinitionArray format
  1639.     if(!is_array($controlDefinitionArray)) {$item1=$controlDefinitionArray;$item2=false;}
  1640.     elseif (count($controlDefinitionArray)==1) {list($item1)=$controlDefinitionArray;$item2=false;}
  1641.     elseif (count($controlDefinitionArray)==2) {list($item1,$item2)=$controlDefinitionArray;}
  1642.     else return false;
  1643.  
  1644.     if($item1){
  1645.         // Check if item1 is an image
  1646.         if(is_file(cfAppDocRoot().$item1)) echo outImage($item1,false,false,$alignStyle);
  1647.         elseif(isset($resourceData['type']) && isset($resourceData['subType']) && file_exists(cfAppDocRoot().'/res/'.$resourceData['type'].'/'.$resourceData['subType'].'/'.$item1)) echo outImage('/res/'.$resourceData['type'].'/'.$resourceData['subType'].'/'.$item1, false, $alignStyle);
  1648.         // Else item1 is a caption
  1649.         else  echo '<span  style="'.$alignStyle.'">'.$item1.'</span>';
  1650.     }
  1651.     if($item2){
  1652.         // Check if item2 is an image
  1653.         if(file_exists(cfAppDocRoot().$item2)) echo '<img alt="" style="'.$alignStyle.'" src="'.$item2.'">';
  1654.         elseif(isset($resourceData['type']) && file_exists(cfAppDocRoot().'/res/'.$resourceData['type'].'/'.$resourceData['subType'].'/'.$item2)) echo '<img alt="" style="'.$alignStyle.'" src="/res/'.$resourceData['type'].'/'.$resourceData['subType'].'/'.$item2.'">';
  1655.         // Else item2 is a caption
  1656.         else  echo '<span  style="'.$alignStyle.'">'.$item2.'</span>';
  1657.     }
  1658.     // Insert spacing after caption/image if needed
  1659.     echo "\n";
  1660.     if($align==alignControlLabel && ($item1 || $item2)){
  1661.         $item1=strtolower($item1);
  1662.         $item2=strtolower($item2);
  1663.         if(($item1 && (substr($item1,-4)=='<br>' || substr($item1,-5)=='<br/>'))) return true;
  1664.         if(($item2 && (substr($item2,-4)=='<br>' || substr($item2,-5)=='<br/>'))) return true;
  1665.         echo "  \n";
  1666.     }
  1667.     return true;
  1668. }
  1669.  
  1670. /**
  1671.  * @desc process a resource parameter :
  1672.  *        - set default value
  1673.  *        - modify value if POST parameter received
  1674.  *        - display control for user input
  1675.  *
  1676.  * @param string $dataName : name of data
  1677.  * @param integer $dataType : type of data :
  1678.  *         - dataText : text data
  1679.  *         - dataNumeric : numeric data
  1680.  *         - dataList : fixed list of data
  1681.  *         - dataBoolean boolean
  1682.  *         - dataFolderPath : path to folder
  1683.  *         - dataFilePath : path to file
  1684.  *
  1685.  * @param mixed $defaultValue : default value of data
  1686.  * @param mixed $constraints : authorized values for data (see below). No constraint if set to false
  1687.  * @param mixed $controlDefinition : user control definition (caption, icons,... see below). Control is not displayed if set to false
  1688.  * @return boolean : true if OK, false if function parameters are not correct
  1689.  */
  1690. function rcProcessData($dataName, $dataType, $defaultValue, $constraints, $controlDefinition=false,$lineBreak=true, $sensitiveData=false){
  1691. global $resourceData;
  1692. global $modifiedValuePHPFunction;
  1693. global $resourceNameModified;
  1694.  
  1695.     // Memorize previous data value
  1696.     if(isset($resourceData[$dataName])) $previousValue=$resourceData[$dataName];
  1697.  
  1698.     /*
  1699.     ***************************************************************************************************************************
  1700.     * SET DEFAULT VALUE
  1701.     ***************************************************************************************************************************
  1702.     */
  1703.     if(!isset($resourceData[$dataName])) $resourceData[$dataName]=$defaultValue;
  1704.  
  1705.     /*
  1706.     ***************************************************************************************************************************
  1707.     * PROCESS POST COMMANDS
  1708.     ***************************************************************************************************************************
  1709.     */
  1710.  
  1711.     // correct POST value for booleans
  1712.     if($dataType==dataBoolean && $controlDefinition && isset($_POST['commandSent']) && !isset($_POST[$dataName])) $_POST[$dataName]=false;
  1713.  
  1714.     // Set new value if passed
  1715.     if(isset($_POST[$dataName]) && $controlDefinition!==false) {
  1716.         $requestedValue=cfUTF8Decode($_POST[$dataName],true,false,false);
  1717.         switch($dataType){
  1718.             // Text data
  1719.             case dataText:
  1720.                 if($dataName=='name') $previousName=$resourceData['name'];
  1721.                 if(is_array($constraints) && count($constraints)==2){
  1722.                     list($nbMin,$nbMax)=$constraints;
  1723.                     if(($nbMin===false || strlen($requestedValue)>=$nbMin) && ($nbMax===false || strlen($requestedValue)<=$nbMax)) $resourceData[$dataName]=$requestedValue;
  1724.                 }
  1725.                 elseif (!$constraints) $resourceData[$dataName]=$requestedValue;
  1726.                 if($dataName=='name' && $previousName!=$resourceData['name']) $resourceNameModified=true;
  1727.                 break;
  1728.             // Password
  1729.             case dataPassword:
  1730.                 if($requestedValue && $requestedValue!=='weezoFakePassword') $resourceData[$dataName]=cfStoredPasswordCrypt($requestedValue);
  1731.                 break;
  1732.             // Numeric data
  1733.             case dataNumeric:
  1734.                 if(is_numeric($requestedValue) && is_array($constraints) && count($constraints)==2){
  1735.                     list($nbMin,$nbMax)=$constraints;
  1736.                     if(($nbMin===false || $requestedValue>=$nbMin) && ($nbMax===false || $requestedValue<=$nbMax)) $resourceData[$dataName]=$requestedValue;
  1737.                 }
  1738.                 elseif (is_numeric($requestedValue) && !$constraints) $resourceData[$dataName]=$requestedValue;
  1739.                 break;
  1740.             // List
  1741.             case dataList:
  1742.                 if(is_array($constraints) && in_array($requestedValue,$constraints)) $resourceData[$dataName]=$requestedValue;
  1743.                 break;
  1744.             // Boolean data
  1745.             case dataBoolean:
  1746.                 if($requestedValue=='true' || $requestedValue=='on') $resourceData[$dataName]=true;
  1747.                 else $resourceData[$dataName]=false;
  1748.                 break;
  1749.             // File or folder path
  1750.             case dataFolderPath:
  1751.             case dataFilePath:
  1752.                 $requestedValue=str_replace('\\\\','/',$requestedValue);
  1753.                 if(substr($requestedValue,-1)=='/') $requestedValue=substr($requestedValue,0,strlen($requestedValue)-1);
  1754.                 if($dataType==dataFolderPath){
  1755.                     if(is_dir($requestedValue)) $resourceData[$dataName]=$requestedValue;
  1756.                     elseif($_POST[$dataName]==cfCaption('explorerComputerRoot') && $constraints!='noComputerRoot') $resourceData[$dataName]='computerRoot';
  1757.                     elseif (cfIsAsync()) rcAddAsyncResponse(cfAsyncXMLJSaction('dgn("'.$dataName.'").style.color="red"'));
  1758.                 }
  1759.                 elseif ($dataType==dataFilePath){
  1760.                     if(is_file($requestedValue)) $resourceData[$dataName]=$requestedValue;
  1761.                     elseif (cfIsAsync()) rcAddAsyncResponse(cfAsyncXMLJSaction('dgn("'.$dataName.'").style.color="red"'));
  1762.                 }
  1763.                 if(cfIsSubDir(cfAppDataRootDir(),$resourceData[$dataName])) $resourceData[$dataName]='*appDir*'.substr($resourceData[$dataName],strlen(cfAppDataRootDir()));
  1764.                 break;
  1765.         }
  1766.     }
  1767.  
  1768.     /*
  1769.     ***************************************************************************************************************************
  1770.     * DISPLAY CONTROL
  1771.     ***************************************************************************************************************************
  1772.     */
  1773.     if($controlDefinition){
  1774.         if($sensitiveData) echo '<span class="warning">';
  1775.         switch($dataType){
  1776.             // TEXT OR NUMERIC DATA
  1777.             // Control definition :
  1778.             //     array(input lenght, $controlDefinitionArray) : text input (size=input lenght) with image and/or caption
  1779.             //     array($controlDefinitionArray,input lenght) : image and/or caption with text input (size=input lenght)
  1780.             //     array($controlDefinitionArray,input lenght, $controlDefinitionArray) : image and/or caption with text input (size=input lenght) and image and/or caption
  1781.             case dataText:
  1782.             case dataNumeric:
  1783.                 $inputType='text';
  1784.             case dataPassword:
  1785.                 if(!isset($inputType)) {
  1786.                     $inputType='password';
  1787.                     $inputValue=(cfStoredPasswordDecrypt($resourceData[$dataName]))?'weezoFakePassword':'';
  1788.                 }
  1789.                 else $inputValue=str_replace('"','"',cfUTF8Encode($resourceData[$dataName]));
  1790.  
  1791.                 if(!is_array($controlDefinition)) $controlDefinition=array($controlDefinition,45); // default control : set size at 45
  1792.                 if(count($controlDefinition)==2){
  1793.                     list($item1,$item2)=$controlDefinition;
  1794.                     // Textbox - caption
  1795.                     if(is_numeric($item1)){
  1796.                         echo '<input onKeyUp="eSaveBt(\''.$dataName.'\',this.value)" onChange="eSaveBt(\''.$dataName.'\',this.value)" type="'.$inputType.'" class="textInput" name="'.$dataName.'" size="'.$item1.'" value="'.$inputValue.'">';
  1797.                         rcDisplayLabelAndOrImage($item2,alignControlLabel);
  1798.                     }
  1799.                     // Caption - Textbox
  1800.                     elseif (is_numeric($item2)){
  1801.                         rcDisplayLabelAndOrImage($item1,alignLabelControl);
  1802.                         echo '<input onKeyUp="eSaveBt(\''.$dataName.'\',this.value)" onChange="eSaveBt(\''.$dataName.'\',this.value)" type="'.$inputType.'" class="textInput" name="'.$dataName.'" size="'.$item2.'" value="'.$inputValue.'">';
  1803.                     }
  1804.                 }
  1805.                 // Caption - Textbox - Caption
  1806.                 elseif (count($controlDefinition)==3 && is_numeric($controlDefinition[1])){
  1807.                         list($item1,$item2,$item3)=$controlDefinition;
  1808.                         rcDisplayLabelAndOrImage($item1,alignLabelControl);
  1809.                         echo '<input onKeyUp="eSaveBt(\''.$dataName.'\',this.value)" onChange="eSaveBt(\''.$dataName.'\',this.value)" type="'.$inputType.'" class="textInput" name="'.$dataName.'" size="'.$item2.'" value="'.$inputValue.'">';
  1810.                         rcDisplayLabelAndOrImage($item3,alignControlLabel);
  1811.                 }
  1812.             break;
  1813.  
  1814.             // VALUES LIST : 2 types of controls : <select> droplist or radio buttons
  1815.             // Control definition :
  1816.             // <select> :
  1817.             //        array($controlDefinitionArray, array of items, $controlDefinitionArray)
  1818.             //         items : array(value, caption)
  1819.             //  Radio buttons:
  1820.             //        array of items
  1821.             //         items : array(left-side $controlDefinitionArray, value, right-side $controlDefinitionArray)
  1822.             case dataList:
  1823.                 if(!is_array($controlDefinition) || count($controlDefinition)<2) return false;
  1824.                 if($resourceData[$dataName]===true) $resourceData[$dataName]='true';
  1825.                 if($resourceData[$dataName]===false) $resourceData[$dataName]='false';
  1826.                 //<select>
  1827.                 if(count($controlDefinition)==3 && is_array($controlDefinition[1]) && ((!is_array($controlDefinition[0])) || count($controlDefinition[0])<3)){
  1828.                     list($item1,$item2,$item3)=$controlDefinition;
  1829.                     rcDisplayLabelAndOrImage($item1,alignLabelControl);
  1830.                     echo '<select name="'.$dataName.'" size="1" class="textInput"  onChange="eSaveBt(\''.$dataName.'\',this.value)">';
  1831.                     foreach ($item2 as $value) {if(is_array($value) && count($value)==2) echo '<option value="'.$value[0].'"'.(($resourceData[$dataName]==$value[0])?' selected':'').'>'.$value[1]."</option>\n";}
  1832.                     echo "</select>\n";
  1833.                     rcDisplayLabelAndOrImage($item3,alignControlLabel);
  1834.                 }
  1835.                 else{
  1836.                 // Radio buttons
  1837.                     $radioNb=0;
  1838.                     foreach ($controlDefinition as $value){
  1839.                         if(is_array($value) && count($value)==3){
  1840.                             list($item1,$item2,$item3)=$value;
  1841.                             if($item1) {echo '<span style="cursor:pointer" onclick="dgn(\''.$dataName.'\','.$radioNb.').checked=\'checked\';dgn(\''.$dataName.'\','.$radioNb.').click()">'; rcDisplayLabelAndOrImage($item1,alignControlLabel); echo '</span>';}
  1842.                             else rcDisplayLabelAndOrImage($item1,alignControlLabel);
  1843.                             //rcDisplayLabelAndOrImage($item1,alignLabelControl);
  1844.                             echo '<input type="radio" name="'.$dataName.'" style="cursor:pointer;vertical-align:middle"  onClick="eSaveBt(\''.$dataName.'\',this.value)" value="'.$item2.'" '.(($resourceData[$dataName]==$item2)?'checked="checked"':'').">\n";
  1845.                             if($item3) {echo '<span style="cursor:pointer" onclick="dgn(\''.$dataName.'\','.$radioNb.').checked=\'checked\';dgn(\''.$dataName.'\','.$radioNb.').click()">'; rcDisplayLabelAndOrImage($item3,alignControlLabel); echo '</span>';}
  1846.                             else rcDisplayLabelAndOrImage($item3,alignControlLabel);
  1847.                             $radioNb++;
  1848.                         }
  1849.                     }
  1850.                 }
  1851.             break;
  1852.             // BOOLEAN DATA
  1853.             case dataBoolean:
  1854.                 // Checkbox
  1855.                 // Control definition :
  1856.                 //     array($controlDefinitionArray) : checkbox with image and/or caption
  1857.                 //    array($controlDefinitionArray,$controlDefinitionArray) : 2 radio buttons with image and/or caption
  1858.                 if(!is_array($controlDefinition)) $controlDefinition=array($controlDefinition);
  1859.                 // Checkbox
  1860.                 if(count($controlDefinition)==1){
  1861.                     echo '<input type="checkbox" onChange="eSaveBt(\''.$dataName.'\',this.checked)" onClick="eSaveBt(\''.$dataName.'\',this.checked)" name="'.$dataName.'" '.(($resourceData[$dataName])?'checked':'').' style="vertical-align:middle"/>';
  1862.                     echo '<span onclick="obj=dgn(\''.$dataName.'\');if(obj.disabled) return; obj.checked=!obj.checked;eSaveBt(\''.$dataName.'\',obj.checked);">';
  1863.                     rcDisplayLabelAndOrImage($controlDefinition[0],alignControlLabel);
  1864.                     echo '</span>';
  1865.                 }
  1866.                 // Radio button (Warning : first item is always true, second is always false)
  1867.                 elseif(count($controlDefinition)==2){
  1868.                     $first=true;
  1869.                     foreach ($controlDefinition as $value){
  1870.                         // radio button
  1871.  
  1872.                         // "true" button
  1873.                         if($first) echo '<input onChange="eSaveBt(\''.$dataName.'\',this.value)" onClick="eSaveBt(\''.$dataName.'\',this.value)" type = "radio" name="'.$dataName.'" value="true" '.(($resourceData[$dataName])?'checked':'').' style="vertical-align:middle">';
  1874.                         // "false" button
  1875.                         else echo '<input onChange="eSaveBt(\''.$dataName.'\',!this.value)" onClick="eSaveBt(\''.$dataName.'\',!this.value)" type = "radio" name="'.$dataName.'" value="false" '.((!$resourceData[$dataName])?'checked':'').' style="vertical-align:middle">';
  1876.  
  1877.                         // Image or label
  1878.                         echo '<span onclick="obj=document.getElementsByName(\''.$dataName.'\')['.(($first)?'0':'1').'];if(obj.disabled) return;obj.checked=true;eSaveBt(\''.$dataName.'\','.(($first)?'!':'').'this.checked);">';
  1879.                         rcDisplayLabelAndOrImage($value,alignControlLabel);
  1880.                         echo '</span>';
  1881.                         if($first) $first=false;
  1882.                     }
  1883.                 }
  1884.             break;
  1885.  
  1886.             // FILE OR DIRECTORY
  1887.             // Control definition :
  1888.             //    optional string : caption
  1889.             case dataFolderPath:
  1890.             case dataFilePath:
  1891.                 // Corrects file/path case
  1892.                 $path=cfCorrectFilenameCase(str_replace('*appDir*',cfAppDataRootDir(),$resourceData[$dataName]),true);
  1893.                 if(cfIsSubDir(cfAppDataRootDir(),$path)) $resourceData[$dataName]='*appDir*'.substr($path,strlen(cfAppDataRootDir())); else $resourceData[$dataName]=$path;
  1894.  
  1895.                 if(is_array($controlDefinition)||substr($controlDefinition,0,4)!='<img') echo '<img alt="" src="'.(($dataType==dataFolderPath)?outIcon('folder'):outIcon('blankFile')).'" style="vertical-align:middle; margin-right:0.5em;">';
  1896.                 // Caption
  1897.                 if($controlDefinition!==true && !is_array($controlDefinition)) echo $controlDefinition;
  1898.                 elseif($dataType==dataFolderPath) echo '<b>'.cfCaption('genDirectory').'</b>';
  1899.                 else echo cfCaption('genFile');
  1900.                 // Input text box
  1901.                 echo '<input class="textInput" onKeyUp="eSaveBt(\''.$dataName.'\',this.value);this.style.color=\'\';" onchange="eSaveBt(\''.$dataName.'\',this.value);" type="text" name="'.$dataName.'" id="'.$dataName.'" size="32" style="margin-left:1em;margin-right:1em;'.(($path!='computerRoot' && !file_exists($path))?'color:red;':'').'" value="'.(($path=='computerRoot')?cfCaption('explorerComputerRoot'):cfUTF8Encode($path)).'">';
  1902.                 if($dataType==dataFolderPath){
  1903.                     // Folder selection button (application environment only)
  1904.                     if(cfIsInApp())
  1905.                         echo outButton(cfCaption('genBrowse'),"javascript:wl.UICommand('openFolder','".$dataName."')",outIcon('fi/folder'),cfCaption("genDirectory"),false,'onclick="eSaveBt(\''.$dataName.'\',this.value)"');
  1906.                     // Computer root button
  1907.                     if($constraints!='noComputerRoot') echo outButton('','javascript:dgi(\''.$dataName.'\').value=\''.cfCaption('explorerComputerRoot').'\';eSaveBt(\''.$dataName.'\',this.value);', outIcon('computerRoot'),cfCaption("explorerComputerRoot"));
  1908.                     // Special : 'path' data is commonly used as base directory for explorer resources - show help button
  1909.                     if($dataName=='path') echo '   '.outHelpButton('helpPath');
  1910.                 }
  1911.                 else{
  1912.                     // File selection button (application environment only)
  1913.                     if(cfIsInApp())
  1914.                         echo outButton(cfCaption('genBrowse'),"javascript:wl.UICommand('openFile','".$dataName.";".$constraints."')",outIcon('explorer'),false,false,'onclick="eSaveBt(\''.$dataName.'\',this.value)"');
  1915.                 }
  1916.  
  1917.             break;
  1918.         }
  1919.     if($sensitiveData) echo '</span>';
  1920.  
  1921.     // Line break
  1922.     if($lineBreak) echo "<br>\n";
  1923.     }
  1924.  
  1925.  
  1926.     // If a callback function has been set (rcSetModifiedValuePHPFunction) and data has changed,
  1927.     // call callbackfunction with dataName and previousValue parameters
  1928.     if(isset($modifiedValuePHPFunction)){
  1929.         if(!isset($previousValue)) $modifiedValuePHPFunction($dataName,false);
  1930.         elseif($previousValue!=$resourceData[$dataName]) $modifiedValuePHPFunction($dataName,$previousValue);
  1931.     }
  1932. }
  1933. ?>